Merge commit 'e260e580' into manualmerge
diff --git a/README.txt b/README.txt
index 6955945..a7dd7da 100644
--- a/README.txt
+++ b/README.txt
@@ -1,5 +1,5 @@
-This directory contains the Dalvik virtual machine and associated
-class library.
+This directory contains the Dalvik virtual machine and core class library,
+as well as related tools, libraries, and tests.
A note about the licenses and header comments
---------------------------------------------
diff --git a/dalvikvm/Main.c b/dalvikvm/Main.c
index 70cc61f..a6439fb 100644
--- a/dalvikvm/Main.c
+++ b/dalvikvm/Main.c
@@ -115,7 +115,7 @@
}
getModifiersId = (*env)->GetMethodID(env, methodClass,
"getModifiers", "()I");
- if (methodClass == NULL) {
+ if (getModifiersId == NULL) {
fprintf(stderr, "Dalvik VM unable to find reflect.Method.getModifiers\n");
goto bail;
}
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
index c5714ea..6fed7aa 100644
--- a/dexdump/DexDump.c
+++ b/dexdump/DexDump.c
@@ -60,10 +60,12 @@
/* command-line options */
struct {
+ bool checksumOnly;
bool disassemble;
bool showFileHeaders;
bool showSectionHeaders;
bool ignoreBadChecksum;
+ bool dumpRegisterMaps;
OutputFormat outputFormat;
const char* tempFileName;
bool exportsOnly;
@@ -86,6 +88,14 @@
}
/*
+ * 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
* equivalent.
*/
@@ -589,10 +599,6 @@
void dumpInstruction(DexFile* pDexFile, const DexCode* pCode, int insnIdx,
int insnWidth, const DecodedInstruction* pDecInsn)
{
- static const float gSpecialTab[16] = {
- -2.0f, -1.0f, -0.5f, -0.25f, -0.1f, 0.1f, 0.25f, 0.5f,
- 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 10.0f, 100.0f, 1000.0f
- };
const u2* insns = pCode->insns;
int i;
@@ -1197,6 +1203,8 @@
/*
* Dump the class.
*
+ * Note "idx" is a DexClassDef index, not a DexTypeId index.
+ *
* If "*pLastPackage" is NULL or does not match the current class' package,
* the value will be replaced with a newly-allocated string.
*/
@@ -1369,6 +1377,208 @@
free(accessStr);
}
+
+/*
+ * Advance "ptr" to ensure 32-bit alignment.
+ */
+static inline const u1* align32(const u1* ptr)
+{
+ return (u1*) (((int) ptr + 3) & ~0x03);
+}
+
+
+/*
+ * Dump a map in the "differential" format.
+ *
+ * TODO: show a hex dump of the compressed data. (We can show the
+ * uncompressed data if we move the compression code to libdex; otherwise
+ * it's too complex to merit a fast & fragile implementation here.)
+ */
+void dumpDifferentialCompressedMap(const u1** pData)
+{
+ const u1* data = *pData;
+ const u1* dataStart = data -1; // format byte already removed
+ u1 regWidth;
+ u2 numEntries;
+
+ /* standard header */
+ regWidth = *data++;
+ numEntries = *data++;
+ numEntries |= (*data++) << 8;
+
+ /* compressed data begins with the compressed data length */
+ int compressedLen = readUnsignedLeb128(&data);
+ int addrWidth = 1;
+ if ((*data & 0x80) != 0)
+ addrWidth++;
+
+ int origLen = 4 + (addrWidth + regWidth) * numEntries;
+ int compLen = (data - dataStart) + compressedLen;
+
+ printf(" (differential compression %d -> %d [%d -> %d])\n",
+ origLen, compLen,
+ (addrWidth + regWidth) * numEntries, compressedLen);
+
+ /* skip past end of entry */
+ data += compressedLen;
+
+ *pData = data;
+}
+
+/*
+ * Dump register map contents of the current method.
+ *
+ * "*pData" should point to the start of the register map data. Advances
+ * "*pData" to the start of the next map.
+ */
+void dumpMethodMap(DexFile* pDexFile, const DexMethod* pDexMethod, int idx,
+ const u1** pData)
+{
+ const u1* data = *pData;
+ const DexMethodId* pMethodId;
+ const char* name;
+ int offset = data - (u1*) pDexFile->pOptHeader;
+
+ pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
+ name = dexStringById(pDexFile, pMethodId->nameIdx);
+ printf(" #%d: 0x%08x %s\n", idx, offset, name);
+
+ u1 format;
+ int addrWidth;
+
+ format = *data++;
+ if (format == 1) { /* kRegMapFormatNone */
+ /* no map */
+ printf(" (no map)\n");
+ addrWidth = 0;
+ } else if (format == 2) { /* kRegMapFormatCompact8 */
+ addrWidth = 1;
+ } else if (format == 3) { /* kRegMapFormatCompact16 */
+ addrWidth = 2;
+ } else if (format == 4) { /* kRegMapFormatDifferential */
+ dumpDifferentialCompressedMap(&data);
+ goto bail;
+ } else {
+ printf(" (unknown format %d!)\n", format);
+ /* don't know how to skip data; failure will cascade to end of class */
+ goto bail;
+ }
+
+ if (addrWidth > 0) {
+ u1 regWidth;
+ u2 numEntries;
+ int idx, addr, byte;
+
+ regWidth = *data++;
+ numEntries = *data++;
+ numEntries |= (*data++) << 8;
+
+ for (idx = 0; idx < numEntries; idx++) {
+ addr = *data++;
+ if (addrWidth > 1)
+ addr |= (*data++) << 8;
+
+ printf(" %4x:", addr);
+ for (byte = 0; byte < regWidth; byte++) {
+ printf(" %02x", *data++);
+ }
+ printf("\n");
+ }
+ }
+
+bail:
+ //if (addrWidth >= 0)
+ // *pData = align32(data);
+ *pData = data;
+}
+
+/*
+ * Dump the contents of the register map area.
+ *
+ * These are only present in optimized DEX files, and the structure is
+ * not really exposed to other parts of the VM itself. We're going to
+ * dig through them here, but this is pretty fragile. DO NOT rely on
+ * this or derive other code from it.
+ */
+void dumpRegisterMaps(DexFile* pDexFile)
+{
+ const u1* pClassPool = pDexFile->pRegisterMapPool;
+ const u4* classOffsets;
+ const u1* ptr;
+ u4 numClasses;
+ int baseFileOffset = (u1*) pClassPool - (u1*) pDexFile->pOptHeader;
+ int idx;
+
+ if (pClassPool == NULL) {
+ printf("No register maps found\n");
+ return;
+ }
+
+ ptr = pClassPool;
+ numClasses = get4LE(ptr);
+ ptr += sizeof(u4);
+ classOffsets = (const u4*) ptr;
+
+ printf("RMAP begins at offset 0x%07x\n", baseFileOffset);
+ printf("Maps for %d classes\n", numClasses);
+ for (idx = 0; idx < (int) numClasses; idx++) {
+ const DexClassDef* pClassDef;
+ const char* classDescriptor;
+
+ pClassDef = dexGetClassDef(pDexFile, idx);
+ classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
+
+ printf("%4d: +%d (0x%08x) %s\n", idx, classOffsets[idx],
+ baseFileOffset + classOffsets[idx], classDescriptor);
+
+ if (classOffsets[idx] == 0)
+ continue;
+
+ /*
+ * What follows is a series of RegisterMap entries, one for every
+ * direct method, then one for every virtual method.
+ */
+ DexClassData* pClassData;
+ const u1* pEncodedData;
+ const u1* data = (u1*) pClassPool + classOffsets[idx];
+ u2 methodCount;
+ int i;
+
+ pEncodedData = dexGetClassData(pDexFile, pClassDef);
+ pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL);
+ if (pClassData == NULL) {
+ fprintf(stderr, "Trouble reading class data\n");
+ continue;
+ }
+
+ methodCount = *data++;
+ methodCount |= (*data++) << 8;
+ data += 2; /* two pad bytes follow methodCount */
+ if (methodCount != pClassData->header.directMethodsSize
+ + pClassData->header.virtualMethodsSize)
+ {
+ printf("NOTE: method count discrepancy (%d != %d + %d)\n",
+ methodCount, pClassData->header.directMethodsSize,
+ pClassData->header.virtualMethodsSize);
+ /* this is bad, but keep going anyway */
+ }
+
+ printf(" direct methods: %d\n",
+ pClassData->header.directMethodsSize);
+ for (i = 0; i < (int) pClassData->header.directMethodsSize; i++) {
+ dumpMethodMap(pDexFile, &pClassData->directMethods[i], i, &data);
+ }
+
+ printf(" virtual methods: %d\n",
+ pClassData->header.virtualMethodsSize);
+ for (i = 0; i < (int) pClassData->header.virtualMethodsSize; i++) {
+ dumpMethodMap(pDexFile, &pClassData->virtualMethods[i], i, &data);
+ }
+
+ free(pClassData);
+ }
+}
+
/*
* Dump the requested sections of the file.
*/
@@ -1382,6 +1592,11 @@
pDexFile->pHeader->magic +4);
}
+ if (gOptions.dumpRegisterMaps) {
+ dumpRegisterMaps(pDexFile);
+ return;
+ }
+
if (gOptions.showFileHeaders)
dumpFileHeader(pDexFile);
@@ -1433,7 +1648,11 @@
goto bail;
}
- processDexFile(fileName, pDexFile);
+ if (gOptions.checksumOnly) {
+ printf("Checksum verified\n");
+ } else {
+ processDexFile(fileName, pDexFile);
+ }
result = 0;
@@ -1453,14 +1672,16 @@
{
fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
fprintf(stderr,
- "%s: [-d] [-f] [-h] [-i] [-l layout] [-t tempfile] dexfile...\n",
+ "%s: [-c] [-d] [-f] [-h] [-i] [-l layout] [-m] [-t tempfile] dexfile...\n",
gProgName);
fprintf(stderr, "\n");
+ fprintf(stderr, " -c : verify checksum and exit\n");
fprintf(stderr, " -d : disassemble code sections\n");
fprintf(stderr, " -f : display summary information from file header\n");
fprintf(stderr, " -h : display file header details\n");
fprintf(stderr, " -i : ignore checksum failures\n");
fprintf(stderr, " -l : output layout, either 'plain' or 'xml'\n");
+ fprintf(stderr, " -m : dump register maps (and nothing else)\n");
fprintf(stderr, " -t : temp file name (defaults to /sdcard/dex-temp-*)\n");
}
@@ -1478,11 +1699,14 @@
gOptions.verbose = true;
while (1) {
- ic = getopt(argc, argv, "dfhil:t:");
+ ic = getopt(argc, argv, "cdfhil:mt:");
if (ic < 0)
break;
switch (ic) {
+ case 'c': // verify the checksum then exit
+ gOptions.checksumOnly = true;
+ break;
case 'd': // disassemble Dalvik instructions
gOptions.disassemble = true;
break;
@@ -1506,6 +1730,9 @@
wantUsage = true;
}
break;
+ case 'm': // dump register maps only
+ gOptions.dumpRegisterMaps = true;
+ break;
case 't': // temp file, used when opening compressed Jar
gOptions.tempFileName = optarg;
break;
@@ -1520,6 +1747,11 @@
wantUsage = true;
}
+ if (gOptions.checksumOnly && gOptions.ignoreBadChecksum) {
+ fprintf(stderr, "Can't specify both -c and -i\n");
+ wantUsage = true;
+ }
+
/* initialize some VM tables */
gInstrWidth = dexCreateInstrWidthTable();
gInstrFormat = dexCreateInstrFormatTable();
@@ -1529,12 +1761,14 @@
return 2;
}
- while (optind < argc)
- process(argv[optind++]);
+ int result = 0;
+ while (optind < argc) {
+ result |= process(argv[optind++]);
+ }
free(gInstrWidth);
free(gInstrFormat);
- return 0;
+ return (result != 0);
}
diff --git a/dexopt/OptMain.c b/dexopt/OptMain.c
index ef339cd..953db0b 100644
--- a/dexopt/OptMain.c
+++ b/dexopt/OptMain.c
@@ -337,7 +337,7 @@
*/
GET_ARG(vmBuildVersion, strtol, "bad vm build");
if (vmBuildVersion != DALVIK_VM_BUILD) {
- LOGE("Inconsistent build rev: %d vs %d\n",
+ LOGE("DexOpt: build rev does not match VM: %d vs %d\n",
vmBuildVersion, DALVIK_VM_BUILD);
goto bail;
}
diff --git a/docs/debugger.html b/docs/debugger.html
index 6e23f0d..7d93caf 100644
--- a/docs/debugger.html
+++ b/docs/debugger.html
@@ -202,6 +202,40 @@
to a program that throws lots of exceptions can result in out-of-memory
errors. This will be fixed in a future release.
</p><p>
+
+</p><p>
+The translation from Java bytecode to Dalvik bytecode may result in
+identical sequences of instructions being combined. This can make it
+look like the wrong bit of code is being executed. For example:
+<pre> int test(int i) {
+ if (i == 1) {
+ return 0;
+ }
+ return 1;
+ }</pre>
+The Dalvik bytecode uses a common <code>return</code> instruction for both
+<code>return</code> statements, so when <code>i</code> is 1 the debugger
+will single-step through <code>return 0</code> and then <code>return 1</code>.
+</p><p>
+
+</p><p>
+Dalvik handles synchronized methods differently from other VMs.
+Instead of marking a method as <code>synchronized</code> and expecting
+the VM to handle the locks, <code>dx</code> inserts a "lock"
+instruction at the top of the method and an "unlock" instruction in a
+synthetic <code>finally</code> block. As a result, when single-stepping
+a <code>return</code> statement, the "current line" cursor may jump to
+the last line in the method.
+</p><p>
+This can also affect the way the debugger processes exceptions. The
+debugger may decide to break on an
+exception based on whether that exception is "caught" or "uncaught". To
+be considered uncaught, there must be no matching <code>catch</code> block
+or <code>finally</code> clause between the current point of execution and
+the top of the thread. An exception thrown within or below a synchronized
+method will always be considered "caught", so the debugger won't stop
+until the exception is re-thrown from the synthetic <code>finally</code> block.
+</p><p>
<address>Copyright © 2009 The Android Open Source Project</address>
diff --git a/docs/embedded-vm-control.html b/docs/embedded-vm-control.html
index f90f0e5..28b19f6 100644
--- a/docs/embedded-vm-control.html
+++ b/docs/embedded-vm-control.html
@@ -15,6 +15,7 @@
<li><a href="#execmode">Execution Mode</a>
<li><a href="#dp">Deadlock Prediction</a>
<li><a href="#stackdump">Stack Dumps</a>
+ <li><a href="#dexcheck">DEX File Checksums</a>
</ul>
<h2><a name="overview">Overview</a></h2>
@@ -235,6 +236,35 @@
<p>If the property is not defined, the VM will write the stack traces to
the Android log when the signal arrives.
+
+<h2><a name="dexcheck">DEX File Checksums</a></h2>
+
+<p>For performance reasons, the checksum on "optimized" DEX files is
+ignored. This is usually safe, because the files are generated on the
+device, and have access permissions that prevent modification.
+
+<p>If the storage on a device becomes unreliable, however, data corruption
+can occur. This usually manifests itself as a repeatable virtual machine
+crash. To speed diagnosis of such failures, the VM provides the
+<code>-Xcheckdexsum</code> argument. When set, the checksums on all DEX
+files are verified before the contents are used.
+
+<p>The application framework will provide this argument during VM
+creation if the <code>dalvik.vm.check-dex-sum</code> property is enabled.
+
+<p>To enable extended DEX checksum verification:
+<pre>adb shell setprop dalvik.vm.check-dex-sum true</pre>
+
+<p>Incorrect checksums will prevent the DEX data from being used, and will
+cause errors to be written to the log file. If a device has a history of
+problems it may be useful to add the property to
+<code>/data/local.prop</code>.
+
+<p>Note also that the
+<code>dexdump</code> tool always verifies DEX checksums, and can be used
+to check for corruption in a large set of files.
+
+
<address>Copyright © 2008 The Android Open Source Project</address>
</body></html>
diff --git a/docs/heap-profiling.html b/docs/heap-profiling.html
new file mode 100644
index 0000000..0a6ce5c
--- /dev/null
+++ b/docs/heap-profiling.html
@@ -0,0 +1,164 @@
+<html>
+<head>
+ <title>Dalvik Heap Profiling</title>
+</head>
+
+<body>
+<h1>Dalvik Heap Profiling</h1>
+
+<p>
+The Dalvik virtual machine can produce a complete dump of the contents
+of the virtual heap. This is very useful for debugging memory usage
+and looking for memory leaks. Getting at the information can be tricky,
+but has become easier in recent releases.
+
+
+<h2>Getting the data</h2>
+<p>
+The first step is to cause the VM to dump its status, and then pull the hprof
+data off. The exact manner for doing so has changed over time.
+</p><p>
+There is a <code>runhat</code> shell function, added by
+<code>build/envsetup.sh</code>, that partially automates these steps. The
+function changes in each release to accommodate newer behavior, so you have
+to be careful that you don't use the wrong version.
+</p><p>
+
+<h3>Early releases (1.0/1.1)</h3>
+<p>
+You can only generate heap data on the emulator or a device with root
+access, because of the way the dump is initiated and where the output
+files go.
+</p><p>
+Get a command shell on the device:
+<blockquote><pre>
+$ adb shell
+</pre></blockquote>
+</p><p>
+You can verify that you're running as root with the <code>id</code> command.
+The response should look like <code>uid=0(root) gid=0(root)</code>. If not,
+type <code>su</code> and try again. If <code>su</code> fails, you're out
+of luck.
+
+</p><p>
+Next, ensure the target directory exists:
+<blockquote><pre>
+# mkdir /data/misc
+# chmod 777 /data/misc
+</pre></blockquote>
+
+</p><p>
+Use <code>ps</code> or DDMS to determine the process ID of your application,
+then send a <code>SIGUSR1</code> to the target process:
+
+<blockquote><pre>
+# kill -10 <pid>
+</pre></blockquote>
+
+</p><p>
+The signal causes a GC, followed by the heap dump (to be completely
+accurate, they actually happen concurrently, but the results in the heap
+dump reflect the post-GC state). This can take a couple of seconds,
+so you have to watch for the GC log message to know when it's complete.
+</p><p>
+Next:
+
+<blockquote><pre>
+# ls /data/misc/heap-dump*
+# exit
+</pre></blockquote>
+
+</p><p>
+Use <code>ls</code> to check the file names, then <code>exit</code> to quit
+the device command shell.
+
+</p><p>
+You should see two output files, named
+<code>/data/misc/heap-dump-BLAH-BLAH.hprof</code> and
+<code>.hprof-head</code>, where BLAH is a runtime-generated value
+that ensures the filename is unique. Pull them off of the device and
+remove the device-side copy:
+
+<blockquote><pre>
+$ adb pull /data/misc/heap-dump-BLAH-BLAH.hprof tail.hprof
+$ adb pull /data/misc/heap-dump-BLAH-BLAH.hprof-head head.hprof
+$ adb shell rm /data/misc/heap-dump-BLAH-BLAH.hprof /data/misc/heap-dump-BLAH-BLAH.hprof-head
+</pre></blockquote>
+
+</p><p>
+Merge them together and remove the intermediates:
+
+<blockquote><pre>
+$ cat head.hprof tail.hprof > dump.hprof
+$ rm head.hprof tail.hprof
+</pre></blockquote>
+
+</p><p>
+You now have the hprof dump in <code>dump.hprof</code>.
+
+</p><p>
+
+
+<h3>"Cupcake" release (1.5)</h3>
+<p>
+Some steps were taken to make this simpler. Notably, the two output
+files are now combined for you, and a new API call was added that allows
+a program to write the dump at will to a specific file. If you're not
+using the API call, you still need to be on an emulator or running as root.
+(For some builds, you can use <code>adb root</code> to restart the adb
+daemon as root.)
+</p><p>
+The basic procedure is the same as for 1.0/1.1, but only one file will
+appear in <code>/data/misc</code> (no <code>-head</code>), and upon
+completion you will see a log message that says "hprof: heap dump completed".
+It looks like this in the log:
+
+<blockquote><pre>
+I/dalvikvm( 289): threadid=7: reacting to signal 10
+I/dalvikvm( 289): SIGUSR1 forcing GC and HPROF dump
+I/dalvikvm( 289): hprof: dumping VM heap to "/data/misc/heap-dump-tm1240861355-pid289.hprof-hptemp".
+I/dalvikvm( 289): hprof: dumping heap strings to "/data/misc/heap-dump-tm1240861355-pid289.hprof".
+I/dalvikvm( 289): hprof: heap dump completed, temp file removed
+</pre></blockquote>
+
+</p><p>
+Summary: as above, use <code>mkdir</code> and <code>chmod</code>
+to ensure the directory exists and is writable by your application.
+Send the <code>SIGUSR1</code> or use the API call to initiate a dump.
+Use <code>adb pull <dump-file></code> and <code>adb shell rm
+<dump-file></code> to retrieve the file and remove it from the
+device. The concatenation step is not needed.
+
+</p><p>
+The new API is in the <code>android.os.Debug</code> class:
+<blockquote><pre>
+public static void dumpHprofData(String fileName) throws IOException
+</pre></blockquote>
+When called, the VM will go through the same series of steps (GC and
+generate a .hprof file), but the output will be written to a file of
+your choice, e.g. <code>/sdcard/myapp.hprof</code>. Because you're
+initiating the action from within the app, and can write the file to
+removable storage or the app's private data area, you can do this on a
+device without root access.
+
+
+<h2>Examining the data</h2>
+<p>
+The data file format was augmented slightly from the common hprof format,
+and due to licensing restrictions the modified <code>hat</code> tool cannot
+be distributed. A conversion tool, <code>hprof-conv</code>, can be used
+to strip the Android-specific portions from the output. This tool was
+first included in 1.5, but will work with older versions of Android.
+</p><p>
+The converted output should work with any hprof data analyzer, including
+<code>jhat</code>, which is available for free in the Sun JDK, and
+Eclipse MAT.
+
+<!-- say something about how to track down common problems, interesting
+ things to look for, ...? -->
+
+</p><p>
+<address>Copyright © 2009 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/docs/hello-world.html b/docs/hello-world.html
new file mode 100644
index 0000000..690c213
--- /dev/null
+++ b/docs/hello-world.html
@@ -0,0 +1,169 @@
+<html>
+<head>
+ <title>Basic Dalvik VM Invocation</title>
+</head>
+
+<body>
+<h1>Basic Dalvik VM Invocation</h1>
+
+<p>
+On an Android device, the Dalvik virtual machine usually executes embedded
+in the Android application framework. It's also possible to run it directly,
+just as you would a virtual machine on your desktop system.
+</p><p>
+After compiling your Java language sources, convert and combine the .class
+files into a DEX file, and push that to the device. Here's a simple example:
+
+</p><p><code>
+% <font color="green">echo 'class Foo {'\</font><br>
+> <font color="green">'public static void main(String[] args) {'\</font><br>
+> <font color="green">'System.out.println("Hello, world"); }}' > Foo.java</font><br>
+% <font color="green">javac Foo.java</font><br>
+% <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
+</code>
+</p><p>
+The <code>-cp</code> option sets the classpath. The initial directory
+for <code>adb shell</code> may not be what you expect it to be, so it's
+usually best to specify absolute pathnames.
+
+</p><p>
+The <code>dx</code> command accepts lists of individual class files,
+directories, or Jar archives. When the <code>--output</code> filename
+ends with <code>.jar</code>, <code>.zip</code>, or <code>.apk</code>,
+a file called <code>classes.dex</code> is created and stored inside the
+archive.
+</p><p>
+Run <code>adb shell dalvikvm -help</code> to see a list of command-line
+options.
+</p><p>
+
+
+
+<h2>Working with the desktop build</h2>
+
+<!-- largely lifted from
+http://groups.google.com/group/android-porting/browse_thread/thread/ab553116dbc960da/29167c58b3b49051#29167c58b3b49051
+-->
+
+<p>
+The Dalvik VM can also be used directly on the desktop. This is somewhat
+more complicated however, because you won't have certain things set up in
+your environment, and several native code libraries are required to support
+the core Dalvik libs.
+</p><p>
+Start with:
+
+<pre>
+ . build/envsetup.sh
+ lunch sim-eng
+</pre>
+
+You should see something like:
+
+<pre>
+ ============================================
+ TARGET_PRODUCT=sim
+ TARGET_BUILD_VARIANT=eng
+ TARGET_SIMULATOR=true
+ TARGET_BUILD_TYPE=debug
+ TARGET_ARCH=x86
+ HOST_ARCH=x86
+ HOST_OS=linux
+ HOST_BUILD_TYPE=release
+ BUILD_ID=
+ ============================================
+</pre>
+
+</p></p>
+This configures you to build for the desktop, linking against glibc.
+This mode is NOT recommended for anything but experimental use. It
+may go away in the future.
+</p></p>
+You may see <code>TARGET_BUILD_TYPE=release</code> or <code>=debug</code>
+or possibly nothing there at all. You may want to replace the
+<code>lunch</code> command with
+<code>choosecombo Simulator debug sim eng</code>.
+</p></p>
+Build the world (add a <code>-j4</code> if you have multiple cores):
+
+<pre>
+ make
+</pre>
+
+</p></p>
+When that completes, you have a working dalvikm on your desktop
+machine:
+
+<pre>
+ % dalvikvm
+ E/dalvikvm(19521): ERROR: must specify non-'.' bootclasspath
+ W/dalvikvm(19521): JNI_CreateJavaVM failed
+ Dalvik VM init failed (check log file)
+</pre>
+
+</p></p>
+To actually do something, you need to specify the bootstrap class path
+and give it a place to put DEX data that it uncompresses from jar
+files. You can do that with a script like this:
+
+<blockquote><pre>
+#!/bin/sh
+
+# base directory, at top of source tree; replace with absolute path
+base=`pwd`
+
+# configure root dir of interesting stuff
+root=$base/out/debug/host/linux-x86/product/sim/system
+export ANDROID_ROOT=$root
+
+# configure bootclasspath
+bootpath=$root/framework
+export BOOTCLASSPATH=$bootpath/core.jar:$bootpath/ext.jar:$bootpath/framework.jar:$bootpath/android.policy.jar:$bootpath/services.jar
+
+# this is where we create the dalvik-cache directory; make sure it exists
+export ANDROID_DATA=/tmp/dalvik_$USER
+mkdir -p $ANDROID_DATA/dalvik-cache
+
+exec dalvikvm $@
+</pre></blockquote>
+
+</p></p>
+The preparation with <code>dx</code> is the same as before:
+
+<pre>
+ % cat > Foo.java
+ class Foo { public static void main(String[] args) {
+ System.out.println("Hello, world");
+ } }
+ (ctrl-D)
+ % javac Foo.java
+ % dx --dex --output=foo.jar Foo.class
+ % ./rund -cp foo.jar Foo
+ Hello, world
+</pre>
+
+As above, you can get some info about valid arguments like this:
+
+<pre>
+ % ./rund -help
+</pre>
+
+</p></p>
+This also shows what options the VM was configured with. The sim "debug"
+build has all sorts of additional assertions and checks enabled,
+which slows the VM down, but since this is just for experiments it
+doesn't matter.
+
+</p></p>
+All of the above applies to x86 Linux. Anything else will likely
+require a porting effort. If libffi supports your system, the amount of
+work required should be minor.
+
+</p></p>
+<address>Copyright © 2009 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/docs/jni-tips.html b/docs/jni-tips.html
index e2c3b85..881f534 100644
--- a/docs/jni-tips.html
+++ b/docs/jni-tips.html
@@ -162,6 +162,12 @@
<code>DeleteGlobalRef</code>.
</p><p>
All JNI methods accept both local and global references as arguments.
+It's possible for references to the same object to have different values;
+for example, the return values from consecutive calls to
+<code>NewGlobalRef</code> on the same object may be different.
+<strong>To see if two references refer to the same object,
+you must use the <code>IsSameObject</code> function.</strong> Never compare
+references with "==" in native code.
</p><p>
Programmers are required to "not excessively allocate" local references. In practical terms this means
that if you're creating large numbers of local references, perhaps while running through an array of
@@ -201,9 +207,10 @@
the string pointer.
</p><p>
-<strong>Don't forget to Release the strings you Get</strong>. The string functions return <code>jchar*</code> or <code>jbyte*</code>, which
-are pointers to primitive types rather than local references. They are
-guaranteed valid until Release is called, which means they are not
+<strong>Don't forget to Release the strings you Get</strong>. The
+string functions return <code>jchar*</code> or <code>jbyte*</code>, which
+are C-style pointers to primitive data rather than local references. They
+are guaranteed valid until Release is called, which means they are not
released when the native method returns.
</p><p>
</p><p>
diff --git a/docs/porting-guide.html b/docs/porting-guide.html
new file mode 100644
index 0000000..fd028cc
--- /dev/null
+++ b/docs/porting-guide.html
@@ -0,0 +1,353 @@
+<html>
+<head>
+ <title>Dalvik Porting Guide</title>
+</head>
+
+<body>
+<h1>Dalvik Porting Guide</h1>
+
+<p>
+The Dalvik virtual machine is intended to run on a variety of platforms.
+The baseline system is expected to be a variant of UNIX (Linux, BSD, Mac
+OS X) running the GNU C compiler. Little-endian CPUs have been exercised
+the most heavily, but big-endian systems are explicitly supported.
+</p><p>
+There are two general categories of work: porting to a Linux system
+with a previously unseen CPU architecture, and porting to a different
+operating system. This document covers the former.
+</p><p>
+Basic familiarity with the Android platform, source code structure, and
+build system is assumed.
+</p>
+
+
+<h2>Core Libraries</h2>
+
+<p>
+The native code in the core libraries (chiefly <code>dalvik/libcore</code>,
+but also <code>dalvik/vm/native</code>) is written in C/C++ and is expected
+to work without modification in a Linux environment. Much of the code
+comes directly from the Apache Harmony project.
+</p><p>
+The core libraries pull in code from many other projects, including
+OpenSSL, zlib, and ICU. These will also need to be ported before the VM
+can be used.
+</p>
+
+
+<h2>JNI Call Bridge</h2>
+
+<p>
+Most of the Dalvik VM runtime is written in portable C. The one
+non-portable component of the runtime is the JNI call bridge. Simply put,
+this converts an array of integers into function arguments of various
+types, and calls a function. This must be done according to the C calling
+conventions for the platform. The task could be as simple as pushing all
+of the arguments onto the stack, or involve complex rules for register
+assignment and stack alignment.
+</p><p>
+To ease porting to new platforms, the <a href="http://sourceware.org/libffi/">
+open-source FFI library</a> (Foreign Function Interface) is used when a
+custom bridge is unavailable. FFI is not as fast as a native implementation,
+and the optional performance improvements it does offer are not used, so
+writing a replacement is a good first step.
+</p><p>
+The code lives in <code>dalvik/vm/arch/*</code>, with the FFI-based version
+in the "generic" directory. There are two source files for each architecture.
+One defines the call bridge itself:
+</p><p><blockquote>
+<code>void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo,
+int argc, const u4* argv, const char* signature, void* func,
+JValue* pReturn)</code>
+</blockquote></p><p>
+This will invoke a C/C++ function declared:
+</p><p><blockquote>
+ <code>return_type func(JNIEnv* pEnv, Object* this [, <i>args</i>])<br></code>
+</blockquote>or (for a "static" method):<blockquote>
+ <code>return_type func(JNIEnv* pEnv, ClassObject* clazz [, <i>args</i>])</code>
+</blockquote></p><p>
+The role of <code>dvmPlatformInvoke</code> is to convert the values in
+<code>argv</code> into C-style calling conventions, call the method, and
+then place the return type into <code>pReturn</code> (a union that holds
+all of the basic JNI types). The code may use the method signature
+(a DEX "shorty" signature, with one character for the return type and one
+per argument) to determine how to handle the values.
+</p><p>
+The other source file involved here defines a 32-bit "hint". The hint
+is computed when the method's class is loaded, and passed in as the
+"argInfo" argument. The hint can be used to avoid scanning the ASCII
+method signature for things like the return value, total argument size,
+or inter-argument 64-bit alignment restrictions.
+
+
+<h2>Interpreter</h2>
+
+<p>
+The Dalvik runtime includes two interpreters, labeled "portable" and "fast".
+The portable interpreter is largely contained within a single C function,
+and should compile on any system that supports gcc. (If you don't have gcc,
+you may need to disable the "threaded" execution model, which relies on
+gcc's "goto table" implementation; look for the THREADED_INTERP define.)
+</p><p>
+The fast interpreter uses hand-coded assembly fragments. If none are
+available for the current architecture, the build system will create an
+interpreter out of C "stubs". The resulting "all stubs" interpreter is
+quite a bit slower than the portable interpreter, making "fast" something
+of a misnomer.
+</p><p>
+The fast interpreter is enabled by default. On platforms without native
+support, you may want to switch to the portable interpreter. This can
+be controlled with the <code>dalvik.vm.execution-mode</code> system
+property. For example, if you:
+</p><p><blockquote>
+<code>adb shell "echo dalvik.vm.execution-mode = int:portable >> /data/local.prop"</code>
+</blockquote></p><p>
+and reboot, the Android app framework will start the VM with the portable
+interpreter enabled.
+</p>
+
+
+<h3>Mterp Interpreter Structure</h3>
+
+<p>
+There may be significant performance advantages to rewriting the
+interpreter core in assembly language, using architecture-specific
+optimizations. In Dalvik this can be done one instruction at a time.
+</p><p>
+The simplest way to implement an interpreter is to have a large "switch"
+statement. After each instruction is handled, the interpreter returns to
+the top of the loop, fetches the next instruction, and jumps to the
+appropriate label.
+</p><p>
+An improvement on this is called "threaded" execution. The instruction
+fetch and dispatch are included at the end of every instruction handler.
+This makes the interpreter a little larger overall, but you get to avoid
+the (potentially expensive) branch back to the top of the switch statement.
+</p><p>
+Dalvik mterp goes one step further, using a computed goto instead of a goto
+table. Instead of looking up the address in a table, which requires an
+extra memory fetch on every instruction, mterp multiplies the opcode number
+by a fixed value. By default, each handler is allowed 64 bytes of space.
+</p><p>
+Not all handlers fit in 64 bytes. Those that don't can have subroutines
+or simply continue on to additional code outside the basic space. Some of
+this is handled automatically by Dalvik, but there's no portable way to detect
+overflow of a 64-byte handler until the VM starts executing.
+</p><p>
+The choice of 64 bytes is somewhat arbitrary, but has worked out well for
+ARM and x86.
+</p><p>
+In the course of development it's useful to have C and assembly
+implementations of each handler, and be able to flip back and forth
+between them when hunting problems down. In mterp this is relatively
+straightforward. You can always see the files being fed to the compiler
+and assembler for your platform by looking in the
+<code>dalvik/vm/mterp/out</code> directory.
+</p><p>
+The interpreter sources live in <code>dalvik/vm/mterp</code>. If you
+haven't yet, you should read <code>dalvik/vm/mterp/README.txt</code> now.
+</p>
+
+
+<h3>Getting Started With Mterp</h3>
+
+</p><p>
+Getting started:
+<ol>
+<li>Decide on the name of your architecture. For the sake of discussion,
+let's call it <code>myarch</code>.
+<li>Make a copy of <code>dalvik/vm/mterp/config-allstubs</code> to
+<code>dalvik/vm/mterp/config-myarch</code>.
+<li>Create a <code>dalvik/vm/mterp/myarch</code> directory to hold your
+source files.
+<li>Add <code>myarch</code> to the list in
+<code>dalvik/vm/mterp/rebuild.sh</code>.
+<li>Make sure <code>dalvik/vm/Android.mk</code> will find the files for
+your architecture. If <code>$(TARGET_ARCH)</code> is configured this
+will happen automatically.
+</ol>
+</p><p>
+You now have the basic framework in place. Whenever you make a change, you
+need to perform two steps: regenerate the mterp output, and build the
+core VM library. (It's two steps because we didn't want the build system
+to require Python 2.5. Which, incidentally, you need to have.)
+<ol>
+<li>In the <code>dalvik/vm/mterp</code> directory, regenerate the contents
+of the files in <code>dalvik/vm/mterp/out</code> by executing
+<code>./rebuild.sh</code>. Note there are two files, one in C and one
+in assembly.
+<li>In the <code>dalvik</code> directory, regenerate the
+<code>libdvm.so</code> library with <code>mm</code>. You can also use
+<code>make libdvm</code> from the top of the tree.
+</ol>
+</p><p>
+This will leave you with an updated libdvm.so, which can be pushed out to
+a device with <code>adb sync</code> or <code>adb push</code>. If you're
+using the emulator, you need to add <code>make snod</code> (System image,
+NO Dependency check) to rebuild the system image file. You should not
+need to do a top-level "make" and rebuild the dependent binaries.
+</p><p>
+At this point you have an "all stubs" interpreter. You can see how it
+works by examining <code>dalvik/vm/mterp/cstubs/entry.c</code>. The
+code runs in a loop, pulling out the next opcode, and invoking the
+handler through a function pointer. Each handler takes a "glue" argument
+that contains all of the useful state.
+</p><p>
+Your goal is to replace the entry method, exit method, and each individual
+instruction with custom implementations. The first thing you need to do
+is create an entry function that calls the handler for the first instruction.
+After that, the instructions chain together, so you don't need a loop.
+(Look at the ARM or x86 implementation to see how they work.)
+</p><p>
+Once you have that, you need something to jump to. You can't branch
+directly to the C stub because it's expecting to be called with a "glue"
+argument and then return. We need a C stub "wrapper" that does the
+setup and jumps directly to the next handler. We write this in assembly
+and then add it to the config file definition.
+</p><p>
+To see how this works, create a file called
+<code>dalvik/vm/mterp/myarch/stub.S</code> that contains one line:
+<pre>
+/* stub for ${opcode} */
+</pre>
+Then, in <code>dalvik/vm/mterp/config-myarch</code>, add this below the
+<code>handler-size</code> directive:
+<pre>
+# source for the instruction table stub
+asm-stub myarch/stub.S
+</pre>
+</p><p>
+Regenerate the sources with <code>./rebuild.sh</code>, and take a look
+inside <code>dalvik/vm/mterp/out/InterpAsm-myarch.S</code>. You should
+see 256 copies of the stub function in a single large block after the
+<code>dvmAsmInstructionStart</code> label. The <code>stub.S</code>
+code will be used anywhere you don't provide an assembly implementation.
+</p><p>
+Note that each block begins with a <code>.balign 64</code> directive.
+This is what pads each handler out to 64 bytes. Note also that the
+<code>${opcode}</code> text changed into an opcode name, which should
+be used to call the C implementation (<code>dvmMterp_${opcode}</code>).
+</p><p>
+The actual contents of <code>stub.S</code> are up to you to define.
+See <code>entry.S</code> and <code>stub.S</code> in the <code>armv5te</code>
+or <code>x86</code> directories for working examples.
+</p><p>
+If you're working on a variation of an existing architecture, you may be
+able to use most of the existing code and just provide replacements for
+a few instructions. Look at the <code>armv4t</code> implementation as
+an example.
+</p>
+
+
+<h3>Replacing Stubs</h3>
+
+<p>
+There are roughly 230 Dalvik opcodes, including some that are inserted by
+<a href="dexopt.html">dexopt</a> and aren't described in the
+<a href="dalvik-bytecode.html">Dalvik bytecode</a> documentation. Each
+one must perform the appropriate actions, fetch the next opcode, and
+branch to the next handler. The actions performed by the assembly version
+must exactly match those performed by the C version (in
+<code>dalvik/vm/mterp/c/OP_*</code>).
+</p><p>
+It is possible to customize the set of "optimized" instructions for your
+platform. This is possible because optimized DEX files are not expected
+to work on multiple devices. Adding, removing, or redefining instructions
+is beyond the scope of this document, and for simplicity it's best to stick
+with the basic set defined by the portable interpreter.
+</p><p>
+Once you have written a handler that looks like it should work, add
+it to the config file. For example, suppose we have a working version
+of <code>OP_NOP</code>. For demonstration purposes, fake it for now by
+putting this into <code>dalvik/vm/mterp/myarch/OP_NOP.S</code>:
+<pre>
+/* This is my NOP handler */
+</pre>
+</p><p>
+Then, in the <code>op-start</code> section of <code>config-myarch</code>, add:
+<pre>
+ op OP_NOP myarch
+</pre>
+</p><p>
+This tells the generation script to use the assembly version from the
+<code>myarch</code> directory instead of the C version from the <code>c</code>
+directory.
+</p><p>
+Execute <code>./rebuild.sh</code>. Look at <code>InterpAsm-myarch.S</code>
+and <code>InterpC-myarch.c</code> in the <code>out</code> directory. You
+will see that the <code>OP_NOP</code> stub wrapper has been replaced with our
+new code in the assembly file, and the C stub implementation is no longer
+included.
+</p><p>
+As you implement instructions, the C version and corresponding stub wrapper
+will disappear from the output files. Eventually you will have a 100%
+assembly interpreter.
+</p>
+
+
+<h3>Interpreter Switching</h3>
+
+<p>
+The Dalvik VM actually includes a third interpreter implementation: the debug
+interpreter. This is a variation of the portable interpreter that includes
+support for debugging and profiling.
+</p><p>
+When a debugger attaches, or a profiling feature is enabled, the VM
+will switch interpreters at a convenient point. This is done at the
+same time as the GC safe point check: on a backward branch, a method
+return, or an exception throw. Similarly, when the debugger detaches
+or profiling is discontinued, execution transfers back to the "fast" or
+"portable" interpreter.
+</p><p>
+Your entry function needs to test the "entryPoint" value in the "glue"
+pointer to determine where execution should begin. Your exit function
+will need to return a boolean that indicates whether the interpreter is
+exiting (because we reached the "bottom" of a thread stack) or wants to
+switch to the other implementation.
+</p><p>
+See the <code>entry.S</code> file in <code>x86</code> or <code>armv5te</code>
+for examples.
+</p>
+
+
+<h3>Testing</h3>
+
+<p>
+A number of VM tests can be found in <code>dalvik/tests</code>. The most
+useful during interpreter development is <code>003-omnibus-opcodes</code>,
+which tests many different instructions.
+</p><p>
+The basic invocation is:
+<pre>
+$ cd dalvik/tests
+$ ./run-test 003
+</pre>
+</p><p>
+This will run test 003 on an attached device or emulator. You can run
+the test against your desktop VM by specifying <code>--reference</code>
+if you suspect the test may be faulty. You can also use
+<code>--portable</code> and <code>--fast</code> to explictly specify
+one Dalvik interpreter or the other.
+</p><p>
+Some instructions are replaced by <code>dexopt</code>, notably when
+"quickening" field accesses and method invocations. To ensure
+that you are testing the basic form of the instruction, add the
+<code>--no-optimize</code> option.
+</p><p>
+There is no in-built instruction tracing mechanism. If you want
+to know for sure that your implementation of an opcode handler
+is being used, the easiest approach is to insert a "printf"
+call. For an example, look at <code>common_squeak</code> in
+<code>dalvik/vm/mterp/armv5te/footer.S</code>.
+</p><p>
+At some point you need to ensure that debuggers and profiling work with
+your interpreter. The easiest way to do this is to simply connect a
+debugger or toggle profiling. (A future test suite may include some
+tests for this.)
+</p>
+
+<p>
+<address>Copyright © 2009 The Android Open Source Project</address>
+
+</body>
+</html>
diff --git a/dx/README.txt b/dx/README.txt
index 5421e7b..6a20c82 100644
--- a/dx/README.txt
+++ b/dx/README.txt
@@ -1,2 +1,3 @@
Home of Dalvik eXchange, the thing that takes in class files and
-reformulates them for consumption in the VM.
+reformulates them for consumption in the VM. It also does a few other
+things; use "dx --help" to see a modicum of self-documentation.
diff --git a/dx/etc/dx b/dx/etc/dx
index dae5874..c2b3c9b 100644
--- a/dx/etc/dx
+++ b/dx/etc/dx
@@ -36,42 +36,50 @@
jarfile=dx.jar
libdir="$progdir"
-if [ ! -r "$libdir/$jarfile" ]
-then
+if [ ! -r "$libdir/$jarfile" ]; then
libdir=`dirname "$progdir"`/tools/lib
fi
-if [ ! -r "$libdir/$jarfile" ]
-then
+
+if [ ! -r "$libdir/$jarfile" ]; then
libdir=`dirname "$progdir"`/framework
fi
-if [ ! -r "$libdir/$jarfile" ]
-then
+
+if [ ! -r "$libdir/$jarfile" ]; then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
+# By default, give dx a max heap size of 1 gig. This can be overridden
+# by using a "-J" option (see below).
+defaultMx="-Xmx1024M"
+
+# The following will extract any initial parameters of the form
+# "-J<stuff>" from the command line and pass them to the Java
+# invocation (instead of to dx). This makes it possible for you to add
+# a command-line parameter such as "-JXmx256M" in your scripts, for
+# example. "java" (with no args) and "java -X" give a summary of
+# available options.
+
javaOpts=""
-# If you want DX to have more memory when executing, uncomment the following
-# line and adjust the value accordingly. Use "java -X" for a list of options
-# you can pass here.
-#
-# javaOpts="-Xmx256M"
-
-# Alternatively, this will extract any parameter "-Jxxx" from the command line
-# and pass them to Java (instead of to dx). This makes it possible for you to
-# add a command-line parameter such as "-JXmx256M" in your ant scripts, for
-# example.
while expr "x$1" : 'x-J' >/dev/null; do
opt=`expr "$1" : '-J\(.*\)'`
javaOpts="${javaOpts} -${opt}"
+ if expr "x${opt}" : "xXmx[0-9]" >/dev/null; then
+ defaultMx="no"
+ fi
shift
done
-if [ "$OSTYPE" = "cygwin" ] ; then
- jarpath=`cygpath -w "$libdir/$jarfile"`
+if [ "${defaultMx}" != "no" ]; then
+ javaOpts="${javaOpts} ${defaultMx}"
+fi
+
+if [ "$OSTYPE" = "cygwin" ]; then
+ # For Cygwin, convert the jarfile path into native Windows style.
+ jarpath=`cygpath -w "$libdir/$jarfile"`
else
- jarpath="$libdir/$jarfile"
+ jarpath="$libdir/$jarfile"
fi
exec java $javaOpts -jar "$jarpath" "$@"
diff --git a/dx/src/com/android/dx/Version.java b/dx/src/com/android/dx/Version.java
index 02dc7b2..4950d39 100644
--- a/dx/src/com/android/dx/Version.java
+++ b/dx/src/com/android/dx/Version.java
@@ -20,6 +20,6 @@
* Version number for dx.
*/
public class Version {
- /** non-null; version string */
- public static final String VERSION = "1.2";
+ /** {@code non-null;} version string */
+ public static final String VERSION = "1.3";
}
diff --git a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
index 12e1f74..acf5a9e 100644
--- a/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
+++ b/dx/src/com/android/dx/cf/attrib/AttAnnotationDefault.java
@@ -19,24 +19,24 @@
import com.android.dx.rop.cst.Constant;
/**
- * Attribute class for <code>AnnotationDefault</code> attributes.
+ * Attribute class for {@code AnnotationDefault} attributes.
*/
public final class AttAnnotationDefault extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "AnnotationDefault";
- /** non-null; the annotation default value */
+ /** {@code non-null;} the annotation default value */
private final Constant value;
- /** >= 0; attribute data length in the original classfile (not
+ /** {@code >= 0;} attribute data length in the original classfile (not
* including the attribute header) */
private final int byteLength;
/**
* Constructs an instance.
*
- * @param value non-null; the annotation default value
- * @param byteLength >= 0; attribute data length in the original
+ * @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)
*/
public AttAnnotationDefault(Constant value, int byteLength) {
@@ -59,7 +59,7 @@
/**
* Gets the annotation default value.
*
- * @return non-null; the value
+ * @return {@code non-null;} the value
*/
public Constant getValue() {
return value;
diff --git a/dx/src/com/android/dx/cf/attrib/AttCode.java b/dx/src/com/android/dx/cf/attrib/AttCode.java
index f00da2f..89ba895 100644
--- a/dx/src/com/android/dx/cf/attrib/AttCode.java
+++ b/dx/src/com/android/dx/cf/attrib/AttCode.java
@@ -22,35 +22,35 @@
import com.android.dx.util.MutabilityException;
/**
- * Attribute class for standard <code>Code</code> attributes.
+ * Attribute class for standard {@code Code} attributes.
*/
public final class AttCode extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "Code";
- /** >= 0; the stack size */
+ /** {@code >= 0;} the stack size */
private final int maxStack;
- /** >= 0; the number of locals */
+ /** {@code >= 0;} the number of locals */
private final int maxLocals;
- /** non-null; array containing the bytecode per se */
+ /** {@code non-null;} array containing the bytecode per se */
private final BytecodeArray code;
- /** non-null; the exception table */
+ /** {@code non-null;} the exception table */
private final ByteCatchList catches;
- /** non-null; the associated list of attributes */
+ /** {@code non-null;} the associated list of attributes */
private final AttributeList attributes;
/**
* Constructs an instance.
*
- * @param maxStack >= 0; the stack size
- * @param maxLocals >= 0; the number of locals
- * @param code non-null; array containing the bytecode per se
- * @param catches non-null; the exception table
- * @param attributes non-null; the associated list of attributes
+ * @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
+ * @param catches {@code non-null;} the exception table
+ * @param attributes {@code non-null;} the associated list of attributes
*/
public AttCode(int maxStack, int maxLocals, BytecodeArray code,
ByteCatchList catches, AttributeList attributes) {
@@ -101,7 +101,7 @@
/**
* Gets the maximum stack size.
*
- * @return >= 0; the maximum stack size
+ * @return {@code >= 0;} the maximum stack size
*/
public int getMaxStack() {
return maxStack;
@@ -110,7 +110,7 @@
/**
* Gets the number of locals.
*
- * @return >= 0; the number of locals
+ * @return {@code >= 0;} the number of locals
*/
public int getMaxLocals() {
return maxLocals;
@@ -119,7 +119,7 @@
/**
* Gets the bytecode array.
*
- * @return non-null; the bytecode array
+ * @return {@code non-null;} the bytecode array
*/
public BytecodeArray getCode() {
return code;
@@ -128,7 +128,7 @@
/**
* Gets the exception table.
*
- * @return non-null; the exception table
+ * @return {@code non-null;} the exception table
*/
public ByteCatchList getCatches() {
return catches;
@@ -137,7 +137,7 @@
/**
* Gets the associated attribute list.
*
- * @return non-null; the attribute list
+ * @return {@code non-null;} the attribute list
*/
public AttributeList getAttributes() {
return attributes;
diff --git a/dx/src/com/android/dx/cf/attrib/AttConstantValue.java b/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
index a84da43..a7436f3 100644
--- a/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
+++ b/dx/src/com/android/dx/cf/attrib/AttConstantValue.java
@@ -24,22 +24,22 @@
import com.android.dx.rop.cst.TypedConstant;
/**
- * Attribute class for standard <code>ConstantValue</code> attributes.
+ * Attribute class for standard {@code ConstantValue} attributes.
*/
public final class AttConstantValue extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "ConstantValue";
- /** non-null; the constant value */
+ /** {@code non-null;} the constant value */
private final TypedConstant constantValue;
/**
* Constructs an instance.
*
- * @param constantValue non-null; the constant value, which must
- * be an instance of one of: <code>CstString</code>,
- * <code>CstInteger</code>, <code>CstLong</code>,
- * <code>CstFloat</code>, or <code>CstDouble</code>
+ * @param constantValue {@code non-null;} the constant value, which must
+ * be an instance of one of: {@code CstString},
+ * {@code CstInteger}, {@code CstLong},
+ * {@code CstFloat}, or {@code CstDouble}
*/
public AttConstantValue(TypedConstant constantValue) {
super(ATTRIBUTE_NAME);
@@ -65,11 +65,11 @@
/**
* Gets the constant value of this instance. The returned value
- * is an instance of one of: <code>CstString</code>,
- * <code>CstInteger</code>, <code>CstLong</code>,
- * <code>CstFloat</code>, or <code>CstDouble</code>.
+ * is an instance of one of: {@code CstString},
+ * {@code CstInteger}, {@code CstLong},
+ * {@code CstFloat}, or {@code CstDouble}.
*
- * @return non-null; the constant value
+ * @return {@code non-null;} the constant value
*/
public TypedConstant getConstantValue() {
return constantValue;
diff --git a/dx/src/com/android/dx/cf/attrib/AttDeprecated.java b/dx/src/com/android/dx/cf/attrib/AttDeprecated.java
index cd1dd24..d440aae 100644
--- a/dx/src/com/android/dx/cf/attrib/AttDeprecated.java
+++ b/dx/src/com/android/dx/cf/attrib/AttDeprecated.java
@@ -17,10 +17,10 @@
package com.android.dx.cf.attrib;
/**
- * Attribute class for standard <code>Deprecated</code> attributes.
+ * Attribute class for standard {@code Deprecated} attributes.
*/
public final class AttDeprecated extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "Deprecated";
/**
diff --git a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
index 7cccad7..68a24d9 100644
--- a/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
+++ b/dx/src/com/android/dx/cf/attrib/AttEnclosingMethod.java
@@ -20,24 +20,24 @@
import com.android.dx.rop.cst.CstType;
/**
- * Attribute class for standards-track <code>EnclosingMethod</code>
+ * Attribute class for standards-track {@code EnclosingMethod}
* attributes.
*/
public final class AttEnclosingMethod extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "EnclosingMethod";
- /** non-null; the innermost enclosing class */
+ /** {@code non-null;} the innermost enclosing class */
private final CstType type;
- /** null-ok; the name-and-type of the innermost enclosing method, if any */
+ /** {@code null-ok;} the name-and-type of the innermost enclosing method, if any */
private final CstNat method;
/**
* Constructs an instance.
*
- * @param type non-null; the innermost enclosing class
- * @param method null-ok; the name-and-type of the innermost enclosing
+ * @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
*/
public AttEnclosingMethod(CstType type, CstNat method) {
@@ -59,7 +59,7 @@
/**
* Gets the innermost enclosing class.
*
- * @return non-null; the innermost enclosing class
+ * @return {@code non-null;} the innermost enclosing class
*/
public CstType getEnclosingClass() {
return type;
@@ -69,7 +69,7 @@
* Gets the name-and-type of the innermost enclosing method, if
* any.
*
- * @return null-ok; the name-and-type of the innermost enclosing
+ * @return {@code null-ok;} the name-and-type of the innermost enclosing
* method, if any
*/
public CstNat getMethod() {
diff --git a/dx/src/com/android/dx/cf/attrib/AttExceptions.java b/dx/src/com/android/dx/cf/attrib/AttExceptions.java
index 59e624e..c592047 100644
--- a/dx/src/com/android/dx/cf/attrib/AttExceptions.java
+++ b/dx/src/com/android/dx/cf/attrib/AttExceptions.java
@@ -20,20 +20,20 @@
import com.android.dx.util.MutabilityException;
/**
- * Attribute class for standard <code>Exceptions</code> attributes.
+ * Attribute class for standard {@code Exceptions} attributes.
*/
public final class AttExceptions extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "Exceptions";
- /** non-null; list of exception classes */
+ /** {@code non-null;} list of exception classes */
private final TypeList exceptions;
/**
* Constructs an instance.
*
- * @param exceptions non-null; list of classes, presumed but not
- * verified to be subclasses of <code>Throwable</code>
+ * @param exceptions {@code non-null;} list of classes, presumed but not
+ * verified to be subclasses of {@code Throwable}
*/
public AttExceptions(TypeList exceptions) {
super(ATTRIBUTE_NAME);
@@ -58,9 +58,9 @@
/**
* Gets the list of classes associated with this instance. In
* general, these classes are not pre-verified to be subclasses of
- * <code>Throwable</code>.
+ * {@code Throwable}.
*
- * @return non-null; the list of classes
+ * @return {@code non-null;} the list of classes
*/
public TypeList getExceptions() {
return exceptions;
diff --git a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
index df30539..bd6c7cd 100644
--- a/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
+++ b/dx/src/com/android/dx/cf/attrib/AttInnerClasses.java
@@ -19,19 +19,19 @@
import com.android.dx.util.MutabilityException;
/**
- * Attribute class for standard <code>InnerClasses</code> attributes.
+ * Attribute class for standard {@code InnerClasses} attributes.
*/
public final class AttInnerClasses extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "InnerClasses";
- /** non-null; list of inner class entries */
+ /** {@code non-null;} list of inner class entries */
private final InnerClassList innerClasses;
/**
* Constructs an instance.
*
- * @param innerClasses non-null; list of inner class entries
+ * @param innerClasses {@code non-null;} list of inner class entries
*/
public AttInnerClasses(InnerClassList innerClasses) {
super(ATTRIBUTE_NAME);
@@ -56,7 +56,7 @@
/**
* Gets the list of "inner class" entries associated with this instance.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public InnerClassList getInnerClasses() {
return innerClasses;
diff --git a/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java b/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
index c5e65e8..38980be 100644
--- a/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
+++ b/dx/src/com/android/dx/cf/attrib/AttLineNumberTable.java
@@ -20,19 +20,19 @@
import com.android.dx.util.MutabilityException;
/**
- * Attribute class for standard <code>LineNumberTable</code> attributes.
+ * Attribute class for standard {@code LineNumberTable} attributes.
*/
public final class AttLineNumberTable extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "LineNumberTable";
- /** non-null; list of line number entries */
+ /** {@code non-null;} list of line number entries */
private final LineNumberList lineNumbers;
/**
* Constructs an instance.
*
- * @param lineNumbers non-null; list of line number entries
+ * @param lineNumbers {@code non-null;} list of line number entries
*/
public AttLineNumberTable(LineNumberList lineNumbers) {
super(ATTRIBUTE_NAME);
@@ -57,7 +57,7 @@
/**
* Gets the list of "line number" entries associated with this instance.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public LineNumberList getLineNumbers() {
return lineNumbers;
diff --git a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
index 893f254..53ba64f 100644
--- a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
+++ b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTable.java
@@ -19,16 +19,16 @@
import com.android.dx.cf.code.LocalVariableList;
/**
- * Attribute class for standard <code>LocalVariableTable</code> attributes.
+ * Attribute class for standard {@code LocalVariableTable} attributes.
*/
public final class AttLocalVariableTable extends BaseLocalVariables {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "LocalVariableTable";
/**
* Constructs an instance.
*
- * @param localVariables non-null; list of local variable entries
+ * @param localVariables {@code non-null;} list of local variable entries
*/
public AttLocalVariableTable(LocalVariableList localVariables) {
super(ATTRIBUTE_NAME, localVariables);
diff --git a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
index 7037b74..49cdb0c 100644
--- a/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
+++ b/dx/src/com/android/dx/cf/attrib/AttLocalVariableTypeTable.java
@@ -19,16 +19,16 @@
import com.android.dx.cf.code.LocalVariableList;
/**
- * Attribute class for standard <code>LocalVariableTypeTable</code> attributes.
+ * Attribute class for standard {@code LocalVariableTypeTable} attributes.
*/
public final class AttLocalVariableTypeTable extends BaseLocalVariables {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "LocalVariableTypeTable";
/**
* Constructs an instance.
*
- * @param localVariables non-null; list of local variable entries
+ * @param localVariables {@code non-null;} list of local variable entries
*/
public AttLocalVariableTypeTable(LocalVariableList localVariables) {
super(ATTRIBUTE_NAME, localVariables);
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
index 583ab17..e83b76f 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleAnnotations.java
@@ -19,18 +19,18 @@
import com.android.dx.rop.annotation.Annotations;
/**
- * Attribute class for standard <code>RuntimeInvisibleAnnotations</code>
+ * Attribute class for standard {@code RuntimeInvisibleAnnotations}
* attributes.
*/
public final class AttRuntimeInvisibleAnnotations extends BaseAnnotations {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "RuntimeInvisibleAnnotations";
/**
* Constructs an instance.
*
- * @param annotations non-null; the list of annotations
- * @param byteLength >= 0; attribute data length in the original
+ * @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)
*/
public AttRuntimeInvisibleAnnotations(Annotations annotations,
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
index 08865e1..7dfe206 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeInvisibleParameterAnnotations.java
@@ -20,19 +20,19 @@
/**
* Attribute class for standard
- * <code>RuntimeInvisibleParameterAnnotations</code> attributes.
+ * {@code RuntimeInvisibleParameterAnnotations} attributes.
*/
public final class AttRuntimeInvisibleParameterAnnotations
extends BaseParameterAnnotations {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME =
"RuntimeInvisibleParameterAnnotations";
/**
* Constructs an instance.
*
- * @param parameterAnnotations non-null; the parameter annotations
- * @param byteLength >= 0; attribute data length in the original
+ * @param parameterAnnotations {@code non-null;} the parameter annotations
+ * @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
*/
public AttRuntimeInvisibleParameterAnnotations(
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
index c61acb5..9de0588 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleAnnotations.java
@@ -19,18 +19,18 @@
import com.android.dx.rop.annotation.Annotations;
/**
- * Attribute class for standard <code>RuntimeVisibleAnnotations</code>
+ * Attribute class for standard {@code RuntimeVisibleAnnotations}
* attributes.
*/
public final class AttRuntimeVisibleAnnotations extends BaseAnnotations {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "RuntimeVisibleAnnotations";
/**
* Constructs an instance.
*
- * @param annotations non-null; the list of annotations
- * @param byteLength >= 0; attribute data length in the original
+ * @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)
*/
public AttRuntimeVisibleAnnotations(Annotations annotations,
diff --git a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
index dfe57b2..76607c0 100644
--- a/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/AttRuntimeVisibleParameterAnnotations.java
@@ -19,20 +19,20 @@
import com.android.dx.rop.annotation.AnnotationsList;
/**
- * Attribute class for standard <code>RuntimeVisibleParameterAnnotations</code>
+ * Attribute class for standard {@code RuntimeVisibleParameterAnnotations}
* attributes.
*/
public final class AttRuntimeVisibleParameterAnnotations
extends BaseParameterAnnotations {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME =
"RuntimeVisibleParameterAnnotations";
/**
* Constructs an instance.
*
- * @param annotations non-null; the parameter annotations
- * @param byteLength >= 0; attribute data length in the original
+ * @param annotations {@code non-null;} the parameter annotations
+ * @param byteLength {@code >= 0;} attribute data length in the original
* classfile (not including the attribute header)
*/
public AttRuntimeVisibleParameterAnnotations(
diff --git a/dx/src/com/android/dx/cf/attrib/AttSignature.java b/dx/src/com/android/dx/cf/attrib/AttSignature.java
index 97edbbd..b9cb97d 100644
--- a/dx/src/com/android/dx/cf/attrib/AttSignature.java
+++ b/dx/src/com/android/dx/cf/attrib/AttSignature.java
@@ -19,19 +19,19 @@
import com.android.dx.rop.cst.CstUtf8;
/**
- * Attribute class for standards-track <code>Signature</code> attributes.
+ * Attribute class for standards-track {@code Signature} attributes.
*/
public final class AttSignature extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "Signature";
- /** non-null; the signature string */
+ /** {@code non-null;} the signature string */
private final CstUtf8 signature;
/**
* Constructs an instance.
*
- * @param signature non-null; the signature string
+ * @param signature {@code non-null;} the signature string
*/
public AttSignature(CstUtf8 signature) {
super(ATTRIBUTE_NAME);
@@ -51,7 +51,7 @@
/**
* Gets the signature string.
*
- * @return non-null; the signature string
+ * @return {@code non-null;} the signature string
*/
public CstUtf8 getSignature() {
return signature;
diff --git a/dx/src/com/android/dx/cf/attrib/AttSourceFile.java b/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
index f087217..941a2b0 100644
--- a/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
+++ b/dx/src/com/android/dx/cf/attrib/AttSourceFile.java
@@ -19,19 +19,19 @@
import com.android.dx.rop.cst.CstUtf8;
/**
- * Attribute class for standard <code>SourceFile</code> attributes.
+ * Attribute class for standard {@code SourceFile} attributes.
*/
public final class AttSourceFile extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "SourceFile";
- /** non-null; name of the source file */
+ /** {@code non-null;} name of the source file */
private final CstUtf8 sourceFile;
/**
* Constructs an instance.
*
- * @param sourceFile non-null; the name of the source file
+ * @param sourceFile {@code non-null;} the name of the source file
*/
public AttSourceFile(CstUtf8 sourceFile) {
super(ATTRIBUTE_NAME);
@@ -51,7 +51,7 @@
/**
* Gets the source file name of this instance.
*
- * @return non-null; the source file
+ * @return {@code non-null;} the source file
*/
public CstUtf8 getSourceFile() {
return sourceFile;
diff --git a/dx/src/com/android/dx/cf/attrib/AttSynthetic.java b/dx/src/com/android/dx/cf/attrib/AttSynthetic.java
index daa9b0c..e3841eb 100644
--- a/dx/src/com/android/dx/cf/attrib/AttSynthetic.java
+++ b/dx/src/com/android/dx/cf/attrib/AttSynthetic.java
@@ -17,10 +17,10 @@
package com.android.dx.cf.attrib;
/**
- * Attribute class for standard <code>Synthetic</code> attributes.
+ * Attribute class for standard {@code Synthetic} attributes.
*/
public final class AttSynthetic extends BaseAttribute {
- /** non-null; attribute name for attributes of this type */
+ /** {@code non-null;} attribute name for attributes of this type */
public static final String ATTRIBUTE_NAME = "Synthetic";
/**
diff --git a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
index 0163e2c..4d9201e 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseAnnotations.java
@@ -23,19 +23,19 @@
* Base class for annotations attributes.
*/
public abstract class BaseAnnotations extends BaseAttribute {
- /** non-null; list of annotations */
+ /** {@code non-null;} list of annotations */
private final Annotations annotations;
- /** >= 0; attribute data length in the original classfile (not
+ /** {@code >= 0;} attribute data length in the original classfile (not
* including the attribute header) */
private final int byteLength;
/**
* Constructs an instance.
*
- * @param attributeName non-null; the name of the attribute
- * @param annotations non-null; the list of annotations
- * @param byteLength >= 0; attribute data length in the original
+ * @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
* classfile (not including the attribute header)
*/
public BaseAnnotations(String attributeName, Annotations annotations,
@@ -64,7 +64,7 @@
/**
* Gets the list of annotations associated with this instance.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public final Annotations getAnnotations() {
return annotations;
diff --git a/dx/src/com/android/dx/cf/attrib/BaseAttribute.java b/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
index ef1c6ac..c9c1b33 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseAttribute.java
@@ -23,13 +23,13 @@
* the attribute name but leaves the rest up to subclasses.
*/
public abstract class BaseAttribute implements Attribute {
- /** non-null; attribute name */
+ /** {@code non-null;} attribute name */
private final String name;
/**
* Constructs an instance.
*
- * @param name non-null; attribute name
+ * @param name {@code non-null;} attribute name
*/
public BaseAttribute(String name) {
if (name == null) {
diff --git a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
index a39e724..5ba5889 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseLocalVariables.java
@@ -20,18 +20,18 @@
import com.android.dx.util.MutabilityException;
/**
- * Base attribute class for standard <code>LocalVariableTable</code>
- * and <code>LocalVariableTypeTable</code> attributes.
+ * Base attribute class for standard {@code LocalVariableTable}
+ * and {@code LocalVariableTypeTable} attributes.
*/
public abstract class BaseLocalVariables extends BaseAttribute {
- /** non-null; list of local variable entries */
+ /** {@code non-null;} list of local variable entries */
private final LocalVariableList localVariables;
/**
* Constructs an instance.
*
- * @param name non-null; attribute name
- * @param localVariables non-null; list of local variable entries
+ * @param name {@code non-null;} attribute name
+ * @param localVariables {@code non-null;} list of local variable entries
*/
public BaseLocalVariables(String name,
LocalVariableList localVariables) {
@@ -57,7 +57,7 @@
/**
* Gets the list of "local variable" entries associated with this instance.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public final LocalVariableList getLocalVariables() {
return localVariables;
diff --git a/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java b/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
index a927e3d..1b204b3 100644
--- a/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
+++ b/dx/src/com/android/dx/cf/attrib/BaseParameterAnnotations.java
@@ -23,19 +23,19 @@
* Base class for parameter annotation list attributes.
*/
public abstract class BaseParameterAnnotations extends BaseAttribute {
- /** non-null; list of annotations */
+ /** {@code non-null;} list of annotations */
private final AnnotationsList parameterAnnotations;
- /** >= 0; attribute data length in the original classfile (not
+ /** {@code >= 0;} attribute data length in the original classfile (not
* including the attribute header) */
private final int byteLength;
/**
* Constructs an instance.
*
- * @param attributeName non-null; the name of the attribute
- * @param parameterAnnotations non-null; the annotations
- * @param byteLength >= 0; attribute data length in the original
+ * @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
* classfile (not including the attribute header)
*/
public BaseParameterAnnotations(String attributeName,
@@ -65,7 +65,7 @@
/**
* Gets the list of annotation lists associated with this instance.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public final AnnotationsList getParameterAnnotations() {
return parameterAnnotations;
diff --git a/dx/src/com/android/dx/cf/attrib/InnerClassList.java b/dx/src/com/android/dx/cf/attrib/InnerClassList.java
index 3585f1d..96e1b60 100644
--- a/dx/src/com/android/dx/cf/attrib/InnerClassList.java
+++ b/dx/src/com/android/dx/cf/attrib/InnerClassList.java
@@ -22,7 +22,7 @@
/**
* List of "inner class" entries, which are the contents of
- * <code>InnerClasses</code> attributes.
+ * {@code InnerClasses} attributes.
*/
public final class InnerClassList extends FixedSizeList {
/**
@@ -37,8 +37,8 @@
/**
* Gets the indicated item.
*
- * @param n >= 0; which item
- * @return null-ok; the indicated item
+ * @param n {@code >= 0;} which item
+ * @return {@code null-ok;} the indicated item
*/
public Item get(int n) {
return (Item) get0(n);
@@ -47,11 +47,11 @@
/**
* Sets the item at the given index.
*
- * @param n >= 0, < size(); which class
- * @param innerClass non-null; class this item refers to
- * @param outerClass null-ok; outer class that this class is a
+ * @param n {@code >= 0, < size();} which class
+ * @param innerClass {@code non-null;} class this item refers to
+ * @param outerClass {@code null-ok;} outer class that this class is a
* member of, if any
- * @param innerName null-ok; original simple name of this class,
+ * @param innerName {@code null-ok;} original simple name of this class,
* if not anonymous
* @param accessFlags original declared access flags
*/
@@ -64,13 +64,13 @@
* Item in an inner classes list.
*/
public static class Item {
- /** non-null; class this item refers to */
+ /** {@code non-null;} class this item refers to */
private final CstType innerClass;
- /** null-ok; outer class that this class is a member of, if any */
+ /** {@code null-ok;} outer class that this class is a member of, if any */
private final CstType outerClass;
- /** null-ok; original simple name of this class, if not anonymous */
+ /** {@code null-ok;} original simple name of this class, if not anonymous */
private final CstUtf8 innerName;
/** original declared access flags */
@@ -79,10 +79,10 @@
/**
* Constructs an instance.
*
- * @param innerClass non-null; class this item refers to
- * @param outerClass null-ok; outer class that this class is a
+ * @param innerClass {@code non-null;} class this item refers to
+ * @param outerClass {@code null-ok;} outer class that this class is a
* member of, if any
- * @param innerName null-ok; original simple name of this
+ * @param innerName {@code null-ok;} original simple name of this
* class, if not anonymous
* @param accessFlags original declared access flags
*/
@@ -101,7 +101,7 @@
/**
* Gets the class this item refers to.
*
- * @return non-null; the class
+ * @return {@code non-null;} the class
*/
public CstType getInnerClass() {
return innerClass;
@@ -110,7 +110,7 @@
/**
* Gets the outer class that this item's class is a member of, if any.
*
- * @return null-ok; the class
+ * @return {@code null-ok;} the class
*/
public CstType getOuterClass() {
return outerClass;
@@ -119,7 +119,7 @@
/**
* Gets the original name of this item's class, if not anonymous.
*
- * @return null-ok; the name
+ * @return {@code null-ok;} the name
*/
public CstUtf8 getInnerName() {
return innerName;
diff --git a/dx/src/com/android/dx/cf/attrib/RawAttribute.java b/dx/src/com/android/dx/cf/attrib/RawAttribute.java
index b89926d..585e5c5 100644
--- a/dx/src/com/android/dx/cf/attrib/RawAttribute.java
+++ b/dx/src/com/android/dx/cf/attrib/RawAttribute.java
@@ -23,11 +23,11 @@
* Raw attribute, for holding onto attributes that are unrecognized.
*/
public final class RawAttribute extends BaseAttribute {
- /** non-null; attribute data */
+ /** {@code non-null;} attribute data */
private final ByteArray data;
/**
- * null-ok; constant pool to use for resolution of cpis in {@link
+ * {@code null-ok;} constant pool to use for resolution of cpis in {@link
* #data}
*/
private final ConstantPool pool;
@@ -35,9 +35,9 @@
/**
* Constructs an instance.
*
- * @param name non-null; attribute name
- * @param data non-null; attribute data
- * @param pool null-ok; constant pool to use for cpi resolution
+ * @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
*/
public RawAttribute(String name, ByteArray data, ConstantPool pool) {
super(name);
@@ -53,11 +53,11 @@
/**
* Constructs an instance from a sub-array of a {@link ByteArray}.
*
- * @param name non-null; attribute name
- * @param data non-null; array containing the attribute data
- * @param offset offset in <code>data</code> to the attribute data
+ * @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
* @param length length of the attribute data, in bytes
- * @param pool null-ok; constant pool to use for cpi resolution
+ * @param pool {@code null-ok;} constant pool to use for cpi resolution
*/
public RawAttribute(String name, ByteArray data, int offset,
int length, ConstantPool pool) {
@@ -67,7 +67,7 @@
/**
* Get the raw data of the attribute.
*
- * @return non-null; the data
+ * @return {@code non-null;} the data
*/
public ByteArray getData() {
return data;
@@ -83,7 +83,7 @@
* presumably came from the class file that this attribute came
* from.
*
- * @return null-ok; the constant pool
+ * @return {@code null-ok;} the constant pool
*/
public ConstantPool getPool() {
return pool;
diff --git a/dx/src/com/android/dx/cf/code/BaseMachine.java b/dx/src/com/android/dx/cf/code/BaseMachine.java
index 430e48b..b7e700d 100644
--- a/dx/src/com/android/dx/cf/code/BaseMachine.java
+++ b/dx/src/com/android/dx/cf/code/BaseMachine.java
@@ -33,44 +33,44 @@
* TypeBearer}.</p>
*/
public abstract class BaseMachine implements Machine {
- /* non-null; the prototype for the associated method */
+ /* {@code non-null;} the prototype for the associated method */
private final Prototype prototype;
- /** non-null; primary arguments */
+ /** {@code non-null;} primary arguments */
private TypeBearer[] args;
- /** >= 0; number of primary arguments */
+ /** {@code >= 0;} number of primary arguments */
private int argCount;
- /** null-ok; type of the operation, if salient */
+ /** {@code null-ok;} type of the operation, if salient */
private Type auxType;
- /** auxiliary <code>int</code> argument */
+ /** auxiliary {@code int} argument */
private int auxInt;
- /** null-ok; auxiliary constant argument */
+ /** {@code null-ok;} auxiliary constant argument */
private Constant auxCst;
/** auxiliary branch target argument */
private int auxTarget;
- /** null-ok; auxiliary switch cases argument */
+ /** {@code null-ok;} auxiliary switch cases argument */
private SwitchList auxCases;
- /** null-ok; auxiliary initial value list for newarray */
+ /** {@code null-ok;} auxiliary initial value list for newarray */
private ArrayList<Constant> auxInitValues;
- /** >= -1; last local accessed */
+ /** {@code >= -1;} last local accessed */
private int localIndex;
- /** null-ok; local target spec, if salient and calculated */
+ /** {@code null-ok;} local target spec, if salient and calculated */
private RegisterSpec localTarget;
- /** non-null; results */
+ /** {@code non-null;} results */
private TypeBearer[] results;
/**
- * >= -1; count of the results, or <code>-1</code> if no results
+ * {@code >= -1;} count of the results, or {@code -1} if no results
* have been set
*/
private int resultCount;
@@ -78,7 +78,7 @@
/**
* Constructs an instance.
*
- * @param prototype non-null; the prototype for the associated method
+ * @param prototype {@code non-null;} the prototype for the associated method
*/
public BaseMachine(Prototype prototype) {
if (prototype == null) {
@@ -254,7 +254,7 @@
/**
* Gets the number of primary arguments.
*
- * @return >= 0; the number of primary arguments
+ * @return {@code >= 0;} the number of primary arguments
*/
protected final int argCount() {
return argCount;
@@ -264,7 +264,7 @@
* Gets the width of the arguments (where a category-2 value counts as
* two).
*
- * @return >= 0; the argument width
+ * @return {@code >= 0;} the argument width
*/
protected final int argWidth() {
int result = 0;
@@ -277,10 +277,10 @@
}
/**
- * Gets the <code>n</code>th primary argument.
+ * Gets the {@code n}th primary argument.
*
- * @param n >= 0, < argCount(); which argument
- * @return non-null; the indicated argument
+ * @param n {@code >= 0, < argCount();} which argument
+ * @return {@code non-null;} the indicated argument
*/
protected final TypeBearer arg(int n) {
if (n >= argCount) {
@@ -298,14 +298,14 @@
/**
* Gets the type auxiliary argument.
*
- * @return null-ok; the salient type
+ * @return {@code null-ok;} the salient type
*/
protected final Type getAuxType() {
return auxType;
}
/**
- * Gets the <code>int</code> auxiliary argument.
+ * Gets the {@code int} auxiliary argument.
*
* @return the argument value
*/
@@ -316,7 +316,7 @@
/**
* Gets the constant auxiliary argument.
*
- * @return null-ok; the argument value
+ * @return {@code null-ok;} the argument value
*/
protected final Constant getAuxCst() {
return auxCst;
@@ -334,7 +334,7 @@
/**
* Gets the switch cases auxiliary argument.
*
- * @return null-ok; the argument value
+ * @return {@code null-ok;} the argument value
*/
protected final SwitchList getAuxCases() {
return auxCases;
@@ -343,7 +343,7 @@
/**
* Gets the init values auxiliary argument.
*
- * @return null-ok; the argument value
+ * @return {@code null-ok;} the argument value
*/
protected final ArrayList<Constant> getInitValues() {
return auxInitValues;
@@ -351,7 +351,7 @@
/**
* Gets the last local index accessed.
*
- * @return >= -1; the salient local index or <code>-1</code> if none
+ * @return {@code >= -1;} the salient local index or {@code -1} if none
* was set since the last time {@link #clearArgs} was called
*/
protected final int getLocalIndex() {
@@ -365,7 +365,7 @@
* should be the sole result set by a call to {@link #setResult} (or
* the combination {@link #clearResult} then {@link #addResult}.
*
- * @return null-ok; the salient register spec or <code>null</code> if no
+ * @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
*/
@@ -417,7 +417,7 @@
* <p><b>Note:</b> If there is more than one result value, the
* others may be added by using {@link #addResult}.</p>
*
- * @param result non-null; result value
+ * @param result {@code non-null;} result value
*/
protected final void setResult(TypeBearer result) {
if (result == null) {
@@ -433,7 +433,7 @@
*
* @see #setResult
*
- * @param result non-null; result value
+ * @param result {@code non-null;} result value
*/
protected final void addResult(TypeBearer result) {
if (result == null) {
@@ -448,7 +448,7 @@
* Gets the count of results. This throws an exception if results were
* never set. (Explicitly clearing the results counts as setting them.)
*
- * @return >= 0; the count
+ * @return {@code >= 0;} the count
*/
protected final int resultCount() {
if (resultCount < 0) {
@@ -462,7 +462,7 @@
* Gets the width of the results (where a category-2 value counts as
* two).
*
- * @return >= 0; the result width
+ * @return {@code >= 0;} the result width
*/
protected final int resultWidth() {
int width = 0;
@@ -475,10 +475,10 @@
}
/**
- * Gets the <code>n</code>th result value.
+ * Gets the {@code n}th result value.
*
- * @param n >= 0, < resultCount(); which result
- * @return non-null; the indicated result value
+ * @param n {@code >= 0, < resultCount();} which result
+ * @return {@code non-null;} the indicated result value
*/
protected final TypeBearer result(int n) {
if (n >= resultCount) {
@@ -499,7 +499,7 @@
* result is stored to that target; otherwise any results are pushed
* onto the stack.
*
- * @param frame non-null; frame to operate on
+ * @param frame {@code non-null;} frame to operate on
*/
protected final void storeResults(Frame frame) {
if (resultCount < 0) {
@@ -529,8 +529,8 @@
* Throws an exception that indicates a mismatch in local variable
* types.
*
- * @param found non-null; the encountered type
- * @param local non-null; the local variable's claimed type
+ * @param found {@code non-null;} the encountered type
+ * @param local {@code non-null;} the local variable's claimed type
*/
public static void throwLocalMismatch(TypeBearer found,
TypeBearer local) {
diff --git a/dx/src/com/android/dx/cf/code/BasicBlocker.java b/dx/src/com/android/dx/cf/code/BasicBlocker.java
index 82e4a08..d67e525 100644
--- a/dx/src/com/android/dx/cf/code/BasicBlocker.java
+++ b/dx/src/com/android/dx/cf/code/BasicBlocker.java
@@ -29,33 +29,37 @@
* Utility that identifies basic blocks in bytecode.
*/
public final class BasicBlocker implements BytecodeArray.Visitor {
- /** non-null; method being converted */
+ /** {@code non-null;} method being converted */
private final ConcreteMethod method;
- /** non-null; work set; bits indicate offsets in need of examination */
+ /**
+ * {@code non-null;} work set; bits indicate offsets in need of
+ * examination
+ */
private final int[] workSet;
/**
- * non-null; live set; bits indicate potentially-live opcodes; contrawise,
- * a bit that isn't on is either in the middle of an instruction or is
- * a definitely-dead opcode
+ * {@code non-null;} live set; bits indicate potentially-live
+ * opcodes; contrawise, a bit that isn't on is either in the
+ * middle of an instruction or is a definitely-dead opcode
*/
private final int[] liveSet;
/**
- * non-null; block start set; bits indicate the starts of basic blocks,
- * including the opcodes that start blocks of definitely-dead code
+ * {@code non-null;} block start set; bits indicate the starts of
+ * basic blocks, including the opcodes that start blocks of
+ * definitely-dead code
*/
private final int[] blockSet;
/**
- * non-null, sparse; for each instruction offset to a branch of
+ * {@code non-null, sparse;} for each instruction offset to a branch of
* some sort, the list of targets for that instruction
*/
private final IntList[] targetLists;
/**
- * non-null, sparse; for each instruction offset to a throwing
+ * {@code non-null, sparse;} for each instruction offset to a throwing
* instruction, the list of exception handlers for that instruction
*/
private final ByteCatchList[] catchLists;
@@ -68,8 +72,8 @@
* returning a list of them. The returned list notably omits any
* definitely-dead code that is identified in the process.
*
- * @param method non-null; method to convert
- * @return non-null; list of basic blocks
+ * @param method {@code non-null;} method to convert
+ * @return {@code non-null;} list of basic blocks
*/
public static ByteBlockList identifyBlocks(ConcreteMethod method) {
BasicBlocker bb = new BasicBlocker(method);
@@ -82,7 +86,7 @@
* Constructs an instance. This class is not publicly instantiable; use
* {@link #identifyBlocks}.
*
- * @param method non-null; method to convert
+ * @param method {@code non-null;} method to convert
*/
private BasicBlocker(ConcreteMethod method) {
if (method == null) {
@@ -262,10 +266,9 @@
/**
* Extracts the list of basic blocks from the bit sets.
*
- * @return non-null; the list of basic blocks
+ * @return {@code non-null;} the list of basic blocks
*/
private ByteBlockList getBlockList() {
- ByteCatchList catches = method.getCatches();
BytecodeArray bytes = method.getCode();
ByteBlock[] bbs = new ByteBlock[bytes.size()];
int count = 0;
@@ -366,7 +369,7 @@
* isn't yet known to be possibly-live.
*
* @param offset offset to the instruction in question
- * @param blockStart <code>true</code> iff this instruction starts a
+ * @param blockStart {@code true} iff this instruction starts a
* basic block
*/
private void addWorkIfNecessary(int offset, boolean blockStart) {
@@ -384,7 +387,7 @@
*
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
- * @param nextIsLive <code>true</code> iff the instruction after
+ * @param nextIsLive {@code true} iff the instruction after
* the indicated one is possibly-live (because this one isn't an
* unconditional branch, a return, or a switch)
*/
@@ -417,7 +420,7 @@
*
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
- * @param nextIsLive <code>true</code> iff the instruction after
+ * @param nextIsLive {@code true} iff the instruction after
* the indicated one is possibly-live (because this one isn't an
* unconditional throw)
*/
diff --git a/dx/src/com/android/dx/cf/code/ByteBlock.java b/dx/src/com/android/dx/cf/code/ByteBlock.java
index 065c522..40b91c3 100644
--- a/dx/src/com/android/dx/cf/code/ByteBlock.java
+++ b/dx/src/com/android/dx/cf/code/ByteBlock.java
@@ -24,32 +24,32 @@
* Representation of a basic block in a bytecode array.
*/
public final class ByteBlock implements LabeledItem {
- /** >= 0; label for this block */
+ /** {@code >= 0;} label for this block */
private final int label;
- /** >= 0; bytecode offset (inclusive) of the start of the block */
+ /** {@code >= 0;} bytecode offset (inclusive) of the start of the block */
private final int start;
- /** > start; bytecode offset (exclusive) of the end of the block */
+ /** {@code > start;} bytecode offset (exclusive) of the end of the block */
private final int end;
- /** non-null; list of successors that this block may branch to */
+ /** {@code non-null;} list of successors that this block may branch to */
private final IntList successors;
- /** non-null; list of exceptions caught and their handler targets */
+ /** {@code non-null;} list of exceptions caught and their handler targets */
private final ByteCatchList catches;
/**
* Constructs an instance.
*
- * @param label >= 0; target label for this block
- * @param start >= 0; bytecode offset (inclusive) of the start
+ * @param label {@code >= 0;} target label for this block
+ * @param start {@code >= 0;} bytecode offset (inclusive) of the start
* of the block
- * @param end > start; bytecode offset (exclusive) of the end
+ * @param end {@code > start;} bytecode offset (exclusive) of the end
* of the block
- * @param successors non-null; list of successors that this block may
+ * @param successors {@code non-null;} list of successors that this block may
* branch to
- * @param catches non-null; list of exceptions caught and their
+ * @param catches {@code non-null;} list of exceptions caught and their
* handler targets
*/
public ByteBlock(int label, int start, int end, IntList successors,
@@ -100,7 +100,7 @@
/**
* Gets the label of this block.
*
- * @return >= 0; the label
+ * @return {@code >= 0;} the label
*/
public int getLabel() {
return label;
@@ -109,7 +109,7 @@
/**
* Gets the bytecode offset (inclusive) of the start of this block.
*
- * @return >= 0; the start offset
+ * @return {@code >= 0;} the start offset
*/
public int getStart() {
return start;
@@ -118,7 +118,7 @@
/**
* Gets the bytecode offset (exclusive) of the end of this block.
*
- * @return > getStart(); the end offset
+ * @return {@code > getStart();} the end offset
*/
public int getEnd() {
return end;
@@ -128,7 +128,7 @@
* Gets the list of successors that this block may branch to
* non-exceptionally.
*
- * @return non-null; the successor list
+ * @return {@code non-null;} the successor list
*/
public IntList getSuccessors() {
return successors;
@@ -137,7 +137,7 @@
/**
* Gets the list of exceptions caught and their handler targets.
*
- * @return non-null; the catch list
+ * @return {@code non-null;} the catch list
*/
public ByteCatchList getCatches() {
return catches;
diff --git a/dx/src/com/android/dx/cf/code/ByteBlockList.java b/dx/src/com/android/dx/cf/code/ByteBlockList.java
index 9d27b7f..412dfc3 100644
--- a/dx/src/com/android/dx/cf/code/ByteBlockList.java
+++ b/dx/src/com/android/dx/cf/code/ByteBlockList.java
@@ -28,7 +28,7 @@
/**
* Constructs an instance.
*
- * @param size >= 0; the number of elements to be in the list
+ * @param size {@code >= 0;} the number of elements to be in the list
*/
public ByteBlockList(int size) {
super(size);
@@ -37,10 +37,10 @@
/**
* 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</code>.
+ * will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which element
- * @return non-null; the indicated element
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
*/
public ByteBlock get(int n) {
return (ByteBlock) get0(n);
@@ -50,7 +50,7 @@
* Gets the block with the given label.
*
* @param label the label to look for
- * @return non-null; the block with the given label
+ * @return {@code non-null;} the block with the given label
*/
public ByteBlock labelToBlock(int label) {
int idx = indexOfLabel(label);
@@ -66,8 +66,8 @@
/**
* Sets the element at the given index.
*
- * @param n >= 0, < size(); which element
- * @param bb null-ok; the value to store
+ * @param n {@code >= 0, < size();} which element
+ * @param bb {@code null-ok;} the value to store
*/
public void set(int n, ByteBlock bb) {
super.set(n, bb);
diff --git a/dx/src/com/android/dx/cf/code/ByteCatchList.java b/dx/src/com/android/dx/cf/code/ByteCatchList.java
index 375831e..aab2087 100644
--- a/dx/src/com/android/dx/cf/code/ByteCatchList.java
+++ b/dx/src/com/android/dx/cf/code/ByteCatchList.java
@@ -24,10 +24,10 @@
/**
* List of catch entries, that is, the elements of an "exception table,"
- * which is part of a standard <code>Code</code> attribute.
+ * which is part of a standard {@code Code} attribute.
*/
public final class ByteCatchList extends FixedSizeList {
- /** non-null; convenient zero-entry instance */
+ /** {@code non-null;} convenient zero-entry instance */
public static final ByteCatchList EMPTY = new ByteCatchList(0);
/**
@@ -41,10 +41,10 @@
/**
* Gets the total length of this structure in bytes, when included in
- * a <code>Code</code> attribute. The returned value includes the
- * two bytes for <code>exception_table_length</code>.
+ * a {@code Code} attribute. The returned value includes the
+ * two bytes for {@code exception_table_length}.
*
- * @return >= 2; the total length, in bytes
+ * @return {@code >= 2;} the total length, in bytes
*/
public int byteLength() {
return 2 + size() * 8;
@@ -53,8 +53,8 @@
/**
* Gets the indicated item.
*
- * @param n >= 0; which item
- * @return null-ok; the indicated item
+ * @param n {@code >= 0;} which item
+ * @return {@code null-ok;} the indicated item
*/
public Item get(int n) {
return (Item) get0(n);
@@ -63,8 +63,8 @@
/**
* Sets the item at the given index.
*
- * @param n >= 0, < size(); which entry to set
- * @param item non-null; the item
+ * @param n {@code >= 0, < size();} which entry to set
+ * @param item {@code non-null;} the item
*/
public void set(int n, Item item) {
if (item == null) {
@@ -77,13 +77,13 @@
/**
* Sets the item at the given index.
*
- * @param n >= 0, < size(); which entry to set
- * @param startPc >= 0; the start pc (inclusive) of the handler's range
- * @param endPc >= startPc; the end pc (exclusive) of the
+ * @param n {@code >= 0, < size();} which entry to set
+ * @param startPc {@code >= 0;} the start pc (inclusive) of the handler's range
+ * @param endPc {@code >= startPc;} the end pc (exclusive) of the
* handler's range
- * @param handlerPc >= 0; the pc of the exception handler
- * @param exceptionClass null-ok; the exception class or
- * <code>null</code> to catch all exceptions with this handler
+ * @param handlerPc {@code >= 0;} the pc of the exception handler
+ * @param exceptionClass {@code null-ok;} the exception class or
+ * {@code null} to catch all exceptions with this handler
*/
public void set(int n, int startPc, int endPc, int handlerPc,
CstType exceptionClass) {
@@ -95,8 +95,8 @@
* automatically made immutable.
*
* @param pc which address
- * @return non-null; list of exception handlers active at
- * <code>pc</code>
+ * @return {@code non-null;} list of exception handlers active at
+ * {@code pc}
*/
public ByteCatchList listFor(int pc) {
int sz = size();
@@ -128,12 +128,12 @@
* Helper method for {@link #listFor}, which tells whether a match
* 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</code> which represents a catch-all.
+ * match or the class {@code Object} which represents a catch-all.
*
- * @param item non-null; item with the exception type to look for
- * @param arr non-null; array to search in
- * @param count non-null; maximum number of elements in the array to check
- * @return <code>true</code> iff the exception type is <i>not</i> found
+ * @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
+ * @return {@code true} iff the exception type is <i>not</i> found
*/
private static boolean typeNotFound(Item item, Item[] arr, int count) {
CstType type = item.getExceptionClass();
@@ -151,13 +151,13 @@
/**
* Returns a target list corresponding to this instance. The result
* is a list of all the exception handler addresses, with the given
- * <code>noException</code> address appended if appropriate. The
+ * {@code noException} address appended if appropriate. The
* result is automatically made immutable.
*
- * @param noException >= -1; the no-exception address to append, or
- * <code>-1</code> not to append anything
- * @return non-null; list of exception targets, with
- * <code>noException</code> appended if necessary
+ * @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
+ * {@code noException} appended if necessary
*/
public IntList toTargetList(int noException) {
if (noException < -1) {
@@ -199,7 +199,7 @@
/**
* Returns a rop-style catches list equivalent to this one.
*
- * @return non-null; the converted instance
+ * @return {@code non-null;} the converted instance
*/
public TypeList toRopCatchList() {
int sz = size();
@@ -221,29 +221,29 @@
* Item in an exception handler list.
*/
public static class Item {
- /** >= 0; the start pc (inclusive) of the handler's range */
+ /** {@code >= 0;} the start pc (inclusive) of the handler's range */
private final int startPc;
- /** >= startPc; the end pc (exclusive) of the handler's range */
+ /** {@code >= startPc;} the end pc (exclusive) of the handler's range */
private final int endPc;
- /** >= 0; the pc of the exception handler */
+ /** {@code >= 0;} the pc of the exception handler */
private final int handlerPc;
- /** null-ok; the exception class or <code>null</code> to catch all
+ /** {@code null-ok;} the exception class or {@code null} to catch all
* exceptions with this handler */
private final CstType exceptionClass;
/**
* Constructs an instance.
*
- * @param startPc >= 0; the start pc (inclusive) of the
+ * @param startPc {@code >= 0;} the start pc (inclusive) of the
* handler's range
- * @param endPc >= startPc; the end pc (exclusive) of the
+ * @param endPc {@code >= startPc;} the end pc (exclusive) of the
* handler's range
- * @param handlerPc >= 0; the pc of the exception handler
- * @param exceptionClass null-ok; the exception class or
- * <code>null</code> to catch all exceptions with this handler
+ * @param handlerPc {@code >= 0;} the pc of the exception handler
+ * @param exceptionClass {@code null-ok;} the exception class or
+ * {@code null} to catch all exceptions with this handler
*/
public Item(int startPc, int endPc, int handlerPc,
CstType exceptionClass) {
@@ -268,7 +268,7 @@
/**
* Gets the start pc (inclusive) of the handler's range.
*
- * @return >= 0; the start pc (inclusive) of the handler's range.
+ * @return {@code >= 0;} the start pc (inclusive) of the handler's range.
*/
public int getStartPc() {
return startPc;
@@ -277,7 +277,7 @@
/**
* Gets the end pc (exclusive) of the handler's range.
*
- * @return >= startPc; the end pc (exclusive) of the
+ * @return {@code >= startPc;} the end pc (exclusive) of the
* handler's range.
*/
public int getEndPc() {
@@ -287,7 +287,7 @@
/**
* Gets the pc of the exception handler.
*
- * @return >= 0; the pc of the exception handler
+ * @return {@code >= 0;} the pc of the exception handler
*/
public int getHandlerPc() {
return handlerPc;
@@ -296,7 +296,7 @@
/**
* Gets the class of exception handled.
*
- * @return non-null; the exception class; {@link CstType#OBJECT}
+ * @return {@code non-null;} the exception class; {@link CstType#OBJECT}
* if this entry handles all possible exceptions
*/
public CstType getExceptionClass() {
@@ -308,7 +308,7 @@
* Returns whether the given address is in the range of this item.
*
* @param pc the address
- * @return <code>true</code> iff this item covers <code>pc</code>
+ * @return {@code true} iff this item covers {@code pc}
*/
public boolean covers(int pc) {
return (pc >= startPc) && (pc < endPc);
diff --git a/dx/src/com/android/dx/cf/code/ByteOps.java b/dx/src/com/android/dx/cf/code/ByteOps.java
index 4c420f6..ea7b514 100644
--- a/dx/src/com/android/dx/cf/code/ByteOps.java
+++ b/dx/src/com/android/dx/cf/code/ByteOps.java
@@ -242,114 +242,114 @@
/** invalid */
public static final int FMT_INVALID = 0;
- /** "-": <code>op</code> */
+ /** "-": {@code op} */
public static final int FMT_NO_ARGS = 1;
- /** "0": <code>op</code>; implies <code>max_locals >= 1</code> */
+ /** "0": {@code op}; implies {@code max_locals >= 1} */
public static final int FMT_NO_ARGS_LOCALS_1 = 2;
- /** "1": <code>op</code>; implies <code>max_locals >= 2</code> */
+ /** "1": {@code op}; implies {@code max_locals >= 2} */
public static final int FMT_NO_ARGS_LOCALS_2 = 3;
- /** "2": <code>op</code>; implies <code>max_locals >= 3</code> */
+ /** "2": {@code op}; implies {@code max_locals >= 3} */
public static final int FMT_NO_ARGS_LOCALS_3 = 4;
- /** "3": <code>op</code>; implies <code>max_locals >= 4</code> */
+ /** "3": {@code op}; implies {@code max_locals >= 4} */
public static final int FMT_NO_ARGS_LOCALS_4 = 5;
- /** "4": <code>op</code>; implies <code>max_locals >= 5</code> */
+ /** "4": {@code op}; implies {@code max_locals >= 5} */
public static final int FMT_NO_ARGS_LOCALS_5 = 6;
- /** "b": <code>op target target</code> */
+ /** "b": {@code op target target} */
public static final int FMT_BRANCH = 7;
- /** "c": <code>op target target target target</code> */
+ /** "c": {@code op target target target target} */
public static final int FMT_WIDE_BRANCH = 8;
- /** "p": <code>op #cpi #cpi</code>; constant restricted as specified */
+ /** "p": {@code op #cpi #cpi}; constant restricted as specified */
public static final int FMT_CPI = 9;
/**
- * "l": <code>op local</code>; category-1 local; implies
- * <code>max_locals</code> is at least two more than the given
+ * "l": {@code op local}; category-1 local; implies
+ * {@code max_locals} is at least two more than the given
* local number
*/
public static final int FMT_LOCAL_1 = 10;
/**
- * "m": <code>op local</code>; category-2 local; implies
- * <code>max_locals</code> is at least two more than the given
+ * "m": {@code op local}; category-2 local; implies
+ * {@code max_locals} is at least two more than the given
* local number
*/
public static final int FMT_LOCAL_2 = 11;
/**
- * "y": <code>op #byte</code> (<code>bipush</code> and
- * <code>newarray</code>)
+ * "y": {@code op #byte} ({@code bipush} and
+ * {@code newarray})
*/
public static final int FMT_LITERAL_BYTE = 12;
- /** "I": <code>invokeinterface cpi cpi count 0</code> */
+ /** "I": {@code invokeinterface cpi cpi count 0} */
public static final int FMT_INVOKEINTERFACE = 13;
- /** "L": <code>ldc #cpi</code>; constant restricted as specified */
+ /** "L": {@code ldc #cpi}; constant restricted as specified */
public static final int FMT_LDC = 14;
- /** "S": <code>sipush #byte #byte</code> */
+ /** "S": {@code sipush #byte #byte} */
public static final int FMT_SIPUSH = 15;
- /** "T": <code>tableswitch ...</code> */
+ /** "T": {@code tableswitch ...} */
public static final int FMT_TABLESWITCH = 16;
- /** "U": <code>lookupswitch ...</code> */
+ /** "U": {@code lookupswitch ...} */
public static final int FMT_LOOKUPSWITCH = 17;
- /** "M": <code>multianewarray cpi cpi dims</code> */
+ /** "M": {@code multianewarray cpi cpi dims} */
public static final int FMT_MULTIANEWARRAY = 18;
- /** "W": <code>wide ...</code> */
+ /** "W": {@code wide ...} */
public static final int FMT_WIDE = 19;
/** mask for the bits representing the opcode format */
public static final int FMT_MASK = 0x1f;
- /** "I": flag bit for valid cp type for <code>Integer</code> */
+ /** "I": flag bit for valid cp type for {@code Integer} */
public static final int CPOK_Integer = 0x20;
- /** "F": flag bit for valid cp type for <code>Float</code> */
+ /** "F": flag bit for valid cp type for {@code Float} */
public static final int CPOK_Float = 0x40;
- /** "J": flag bit for valid cp type for <code>Long</code> */
+ /** "J": flag bit for valid cp type for {@code Long} */
public static final int CPOK_Long = 0x80;
- /** "D": flag bit for valid cp type for <code>Double</code> */
+ /** "D": flag bit for valid cp type for {@code Double} */
public static final int CPOK_Double = 0x100;
- /** "c": flag bit for valid cp type for <code>Class</code> */
+ /** "c": flag bit for valid cp type for {@code Class} */
public static final int CPOK_Class = 0x200;
- /** "s": flag bit for valid cp type for <code>String</code> */
+ /** "s": flag bit for valid cp type for {@code String} */
public static final int CPOK_String = 0x400;
- /** "f": flag bit for valid cp type for <code>Fieldref</code> */
+ /** "f": flag bit for valid cp type for {@code Fieldref} */
public static final int CPOK_Fieldref = 0x800;
- /** "m": flag bit for valid cp type for <code>Methodref</code> */
+ /** "m": flag bit for valid cp type for {@code Methodref} */
public static final int CPOK_Methodref = 0x1000;
- /** "i": flag bit for valid cp type for <code>InterfaceMethodref</code> */
+ /** "i": flag bit for valid cp type for {@code InterfaceMethodref} */
public static final int CPOK_InterfaceMethodref = 0x2000;
/**
- * non-null; map from opcodes to format or'ed with allowed constant
+ * {@code non-null;} map from opcodes to format or'ed with allowed constant
* pool types
*/
private static final int[] OPCODE_INFO = new int[256];
- /** non-null; map from opcodes to their names */
+ /** {@code non-null;} map from opcodes to their names */
private static final String[] OPCODE_NAMES = new String[256];
- /** non-null; bigass string describing all the opcodes */
+ /** {@code non-null;} bigass string describing all the opcodes */
private static final String OPCODE_DETAILS =
"00 - nop;" +
"01 - aconst_null;" +
@@ -623,8 +623,8 @@
/**
* Gets the name of the given opcode.
*
- * @param opcode >= 0, <= 255; the opcode
- * @return non-null; its name
+ * @param opcode {@code >= 0, <= 255;} the opcode
+ * @return {@code non-null;} its name
*/
public static String opName(int opcode) {
String result = OPCODE_NAMES[opcode];
@@ -640,7 +640,7 @@
/**
* Gets the format and allowed cp types of the given opcode.
*
- * @param opcode >= 0, <= 255; the opcode
+ * @param opcode {@code >= 0, <= 255;} the opcode
* @return its format and allowed cp types
*/
public static int opInfo(int opcode) {
diff --git a/dx/src/com/android/dx/cf/code/BytecodeArray.java b/dx/src/com/android/dx/cf/code/BytecodeArray.java
index 71ba029..60f0cee 100644
--- a/dx/src/com/android/dx/cf/code/BytecodeArray.java
+++ b/dx/src/com/android/dx/cf/code/BytecodeArray.java
@@ -32,23 +32,23 @@
import java.util.ArrayList;
/**
- * Bytecode array, which is part of a standard <code>Code</code> attribute.
+ * Bytecode array, which is part of a standard {@code Code} attribute.
*/
public final class BytecodeArray {
/** convenient no-op implementation of {@link Visitor} */
public static final Visitor EMPTY_VISITOR = new BaseVisitor();
- /** non-null; underlying bytes */
+ /** {@code non-null;} underlying bytes */
private final ByteArray bytes;
- /** non-null; constant pool to use when resolving constant pool indices */
+ /** {@code non-null;} constant pool to use when resolving constant pool indices */
private final ConstantPool pool;
/**
* Constructs an instance.
*
- * @param bytes non-null; underlying bytes
- * @param pool non-null; constant pool to use when resolving constant
+ * @param bytes {@code non-null;} underlying bytes
+ * @param pool {@code non-null;} constant pool to use when resolving constant
* pool indices
*/
public BytecodeArray(ByteArray bytes, ConstantPool pool) {
@@ -67,7 +67,7 @@
/**
* Gets the underlying byte array.
*
- * @return non-null; the byte array
+ * @return {@code non-null;} the byte array
*/
public ByteArray getBytes() {
return bytes;
@@ -76,7 +76,7 @@
/**
* Gets the size of the bytecode array, per se.
*
- * @return >= 0; the length of the bytecode array
+ * @return {@code >= 0;} the length of the bytecode array
*/
public int size() {
return bytes.size();
@@ -84,10 +84,10 @@
/**
* Gets the total length of this structure in bytes, when included in
- * a <code>Code</code> attribute. The returned value includes the
- * array size plus four bytes for <code>code_length</code>.
+ * a {@code Code} attribute. The returned value includes the
+ * array size plus four bytes for {@code code_length}.
*
- * @return >= 4; the total length, in bytes
+ * @return {@code >= 4;} the total length, in bytes
*/
public int byteLength() {
return 4 + bytes.size();
@@ -96,7 +96,7 @@
/**
* Parses each instruction in the array, in order.
*
- * @param visitor null-ok; visitor to call back to for each instruction
+ * @param visitor {@code null-ok;} visitor to call back to for each instruction
*/
public void forEach(Visitor visitor) {
int sz = bytes.size();
@@ -116,7 +116,7 @@
* result is a bit set with the offset of each opcode-per-se flipped on.
*
* @see Bits
- * @return non-null; appropriately constructed bit set
+ * @return {@code non-null;} appropriately constructed bit set
*/
public int[] getInstructionOffsets() {
int sz = bytes.size();
@@ -139,8 +139,8 @@
* work set is empty. It is expected that the visitor will regularly
* set new bits in the work set during the process.
*
- * @param workSet non-null; the work set to process
- * @param visitor non-null; visitor to call back to for each instruction
+ * @param workSet {@code non-null;} the work set to process
+ * @param visitor {@code non-null;} visitor to call back to for each instruction
*/
public void processWorkSet(int[] workSet, Visitor visitor) {
if (visitor == null) {
@@ -170,42 +170,42 @@
*
* <ul>
* <li>The opcodes to push literal constants of primitive types all become
- * <code>ldc</code>.
- * E.g., <code>fconst_0</code>, <code>sipush</code>, and
- * <code>lconst_0</code> qualify for this treatment.</li>
- * <li><code>aconst_null</code> becomes <code>ldc</code> of a
+ * {@code ldc}.
+ * 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>
* <li>Shorthand local variable accessors become the corresponding
- * longhand. E.g. <code>aload_2</code> becomes <code>aload</code>.</li>
- * <li><code>goto_w</code> and <code>jsr_w</code> become <code>goto</code>
- * and <code>jsr</code> (respectively).</li>
- * <li><code>ldc_w</code> becomes <code>ldc</code>.</li>
- * <li><code>tableswitch</code> becomes <code>lookupswitch</code>.
+ * longhand. E.g. {@code aload_2} becomes {@code aload}.</li>
+ * <li>{@code goto_w} and {@code jsr_w} become {@code goto}
+ * and {@code jsr} (respectively).</li>
+ * <li>{@code ldc_w} becomes {@code ldc}.</li>
+ * <li>{@code tableswitch} becomes {@code lookupswitch}.
* <li>Arithmetic, array, and value-returning ops are collapsed
- * to the <code>int</code> variant opcode, with the <code>type</code>
+ * to the {@code int} variant opcode, with the {@code type}
* argument set to indicate the actual type. E.g.,
- * <code>fadd</code> becomes <code>iadd</code>, but
- * <code>type</code> is passed as <code>Type.FLOAT</code> in that
- * case. Similarly, <code>areturn</code> becomes
- * <code>ireturn</code>. (However, <code>return</code> remains
+ * {@code fadd} becomes {@code iadd}, but
+ * {@code type} is passed as {@code Type.FLOAT} in that
+ * case. Similarly, {@code areturn} becomes
+ * {@code ireturn}. (However, {@code return} remains
* unchanged.</li>
- * <li>Local variable access ops are collapsed to the <code>int</code>
- * variant opcode, with the <code>type</code> argument set to indicate
- * the actual type. E.g., <code>aload</code> becomes <code>iload</code>,
- * but <code>type</code> is passed as <code>Type.OBJECT</code> in
+ * <li>Local variable access ops are collapsed to the {@code int}
+ * variant opcode, with the {@code type} argument set to indicate
+ * the actual type. E.g., {@code aload} becomes {@code iload},
+ * but {@code type} is passed as {@code Type.OBJECT} in
* that case.</li>
- * <li>Numeric conversion ops (<code>i2l</code>, etc.) are left alone
- * to avoid too much confustion, but their <code>type</code> is
- * the pushed type. E.g., <code>i2b</code> gets type
- * <code>Type.INT</code>, and <code>f2d</code> gets type
- * <code>Type.DOUBLE</code>. Other unaltered opcodes also get
- * their pushed type. E.g., <code>arraylength</code> gets type
- * <code>Type.INT</code>.</li>
+ * <li>Numeric conversion ops ({@code i2l}, etc.) are left alone
+ * to avoid too much confustion, but their {@code type} is
+ * the pushed type. E.g., {@code i2b} gets type
+ * {@code Type.INT}, and {@code f2d} gets type
+ * {@code Type.DOUBLE}. Other unaltered opcodes also get
+ * their pushed type. E.g., {@code arraylength} gets type
+ * {@code Type.INT}.</li>
* </ul>
*
- * @param offset >= 0, < bytes.size(); offset to the start of the
+ * @param offset {@code >= 0, < bytes.size();} offset to the start of the
* instruction
- * @param visitor null-ok; visitor to call back to
+ * @param visitor {@code null-ok;} visitor to call back to
* @return the length of the instruction, in bytes
*/
public int parseInstruction(int offset, Visitor visitor) {
@@ -797,10 +797,10 @@
}
/**
- * Helper to deal with <code>tableswitch</code>.
+ * Helper to deal with {@code tableswitch}.
*
- * @param offset the offset to the <code>tableswitch</code> opcode itself
- * @param visitor non-null; visitor to use
+ * @param offset the offset to the {@code tableswitch} opcode itself
+ * @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
*/
private int parseTableswitch(int offset, Visitor visitor) {
@@ -840,10 +840,10 @@
}
/**
- * Helper to deal with <code>lookupswitch</code>.
+ * Helper to deal with {@code lookupswitch}.
*
- * @param offset the offset to the <code>lookupswitch</code> opcode itself
- * @param visitor non-null; visitor to use
+ * @param offset the offset to the {@code lookupswitch} opcode itself
+ * @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
*/
private int parseLookupswitch(int offset, Visitor visitor) {
@@ -878,10 +878,10 @@
}
/**
- * Helper to deal with <code>newarray</code>.
+ * Helper to deal with {@code newarray}.
*
- * @param offset the offset to the <code>newarray</code> opcode itself
- * @param visitor non-null; visitor to use
+ * @param offset the offset to the {@code newarray} opcode itself
+ * @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
*/
private int parseNewarray(int offset, Visitor visitor) {
@@ -1061,10 +1061,10 @@
/**
- * Helper to deal with <code>wide</code>.
+ * Helper to deal with {@code wide}.
*
- * @param offset the offset to the <code>wide</code> opcode itself
- * @param visitor non-null; visitor to use
+ * @param offset the offset to the {@code wide} opcode itself
+ * @param visitor {@code non-null;} visitor to use
* @return instruction length, in bytes
*/
private int parseWide(int offset, Visitor visitor) {
@@ -1159,7 +1159,7 @@
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
- * @param type non-null; type the instruction operates on
+ * @param type {@code non-null;} type the instruction operates on
*/
public void visitNoArgs(int opcode, int offset, int length,
Type type);
@@ -1171,9 +1171,9 @@
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
* @param idx the local variable index
- * @param type non-null; the type of the accessed value
+ * @param type {@code non-null;} the type of the accessed value
* @param value additional literal integer argument, if salient (i.e.,
- * for <code>iinc</code>)
+ * for {@code iinc})
*/
public void visitLocal(int opcode, int offset, int length,
int idx, Type type, int value);
@@ -1182,23 +1182,23 @@
* Visits an instruction which has a (possibly synthetic)
* constant argument, and possibly also an
* additional literal integer argument. In the case of
- * <code>multianewarray</code>, the argument is the count of
- * dimensions. In the case of <code>invokeinterface</code>,
+ * {@code multianewarray}, the argument is the count of
+ * dimensions. In the case of {@code invokeinterface},
* the argument is the parameter count or'ed with the
* should-be-zero value left-shifted by 8. In the case of entries
- * of type <code>int</code>, the <code>value</code> field always
+ * 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</code> also uses this
- * form, passing <code>value</code> as the array type code and
- * <code>cst</code> as a {@link CstType} instance
+ * 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
- * @param cst non-null; the constant
+ * @param cst {@code non-null;} the constant
* @param value additional literal integer argument, if salient
* (ignore if not)
*/
@@ -1222,7 +1222,7 @@
* @param opcode the opcode
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
- * @param cases non-null; list of (value, target) pairs, plus the
+ * @param cases {@code non-null;} list of (value, target) pairs, plus the
* default target
* @param padding the bytes found in the padding area (if any),
* packed
@@ -1235,8 +1235,8 @@
*
* @param offset offset to the instruction
* @param length length of the instruction, in bytes
- * @param cst non-null; the type of the array
- * @param initVals non-null; list of bytecode offsets for init values
+ * @param cst {@code non-null;} the type of the array
+ * @param initVals {@code non-null;} list of bytecode offsets for init values
*/
public void visitNewarray(int offset, int length, CstType type,
ArrayList<Constant> initVals);
diff --git a/dx/src/com/android/dx/cf/code/ConcreteMethod.java b/dx/src/com/android/dx/cf/code/ConcreteMethod.java
index 47f698d..70b6b45 100644
--- a/dx/src/com/android/dx/cf/code/ConcreteMethod.java
+++ b/dx/src/com/android/dx/cf/code/ConcreteMethod.java
@@ -35,38 +35,38 @@
* Container for all the giblets that make up a concrete Java bytecode method.
* It implements {@link Method}, so it provides all the original access
* (by delegation), but it also constructs and keeps useful versions of
- * stuff extracted from the method's <code>Code</code> attribute.
+ * stuff extracted from the method's {@code Code} attribute.
*/
public final class ConcreteMethod implements Method {
- /** non-null; method being wrapped */
+ /** {@code non-null;} method being wrapped */
private final Method method;
/**
- * null-ok; the class's <code>SourceFile</code> attribute value,
+ * {@code null-ok;} the class's {@code SourceFile} attribute value,
* if any
*/
private final CstUtf8 sourceFile;
/**
* whether the class that this method is part of is defined with
- * <code>ACC_SUPER</code>
+ * {@code ACC_SUPER}
*/
private final boolean accSuper;
- /** non-null; the code attribute */
+ /** {@code non-null;} the code attribute */
private final AttCode attCode;
- /** non-null; line number list */
+ /** {@code non-null;} line number list */
private final LineNumberList lineNumbers;
- /** non-null; local variable list */
+ /** {@code non-null;} local variable list */
private final LocalVariableList localVariables;
/**
* Constructs an instance.
*
- * @param method non-null; the method to be based on
- * @param cf non-null; the class file that contains this method
+ * @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
* (if any)
* @param keepLocals whether to keep the local variable
@@ -178,9 +178,9 @@
/**
* Gets whether the class that this method is part of is defined with
- * <code>ACC_SUPER</code>.
+ * {@code ACC_SUPER}.
*
- * @return the <code>ACC_SUPER</code> value
+ * @return the {@code ACC_SUPER} value
*/
public boolean getAccSuper() {
return accSuper;
@@ -189,7 +189,7 @@
/**
* Gets the maximum stack size.
*
- * @return >= 0; the maximum stack size
+ * @return {@code >= 0;} the maximum stack size
*/
public int getMaxStack() {
return attCode.getMaxStack();
@@ -198,7 +198,7 @@
/**
* Gets the number of locals.
*
- * @return >= 0; the number of locals
+ * @return {@code >= 0;} the number of locals
*/
public int getMaxLocals() {
return attCode.getMaxLocals();
@@ -207,7 +207,7 @@
/**
* Gets the bytecode array.
*
- * @return non-null; the bytecode array
+ * @return {@code non-null;} the bytecode array
*/
public BytecodeArray getCode() {
return attCode.getCode();
@@ -216,7 +216,7 @@
/**
* Gets the exception table.
*
- * @return non-null; the exception table
+ * @return {@code non-null;} the exception table
*/
public ByteCatchList getCatches() {
return attCode.getCatches();
@@ -225,7 +225,7 @@
/**
* Gets the line number list.
*
- * @return non-null; the line number list
+ * @return {@code non-null;} the line number list
*/
public LineNumberList getLineNumbers() {
return lineNumbers;
@@ -234,7 +234,7 @@
/**
* Gets the local variable list.
*
- * @return non-null; the local variable list
+ * @return {@code non-null;} the local variable list
*/
public LocalVariableList getLocalVariables() {
return localVariables;
@@ -244,8 +244,8 @@
* Returns a {@link SourcePosition} instance corresponding to the
* given bytecode offset.
*
- * @param offset >= 0; the bytecode offset
- * @return non-null; an appropriate instance
+ * @param offset {@code >= 0;} the bytecode offset
+ * @return {@code non-null;} an appropriate instance
*/
public SourcePosition makeSourcePosistion(int offset) {
return new SourcePosition(sourceFile, offset,
diff --git a/dx/src/com/android/dx/cf/code/ExecutionStack.java b/dx/src/com/android/dx/cf/code/ExecutionStack.java
index 1a2b565..15a9e6c 100644
--- a/dx/src/com/android/dx/cf/code/ExecutionStack.java
+++ b/dx/src/com/android/dx/cf/code/ExecutionStack.java
@@ -30,11 +30,11 @@
* TypeBearer}.</p>
*/
public final class ExecutionStack extends MutabilityControl {
- /** non-null; array of stack contents */
+ /** {@code non-null;} array of stack contents */
private final TypeBearer[] stack;
/**
- * >= 0; stack pointer (points one past the end) / current stack
+ * {@code >= 0;} stack pointer (points one past the end) / current stack
* size
*/
private int stackPtr;
@@ -42,7 +42,7 @@
/**
* Constructs an instance.
*
- * @param maxStack >= 0; the maximum size of the stack for this
+ * @param maxStack {@code >= 0;} the maximum size of the stack for this
* instance
*/
public ExecutionStack(int maxStack) {
@@ -54,7 +54,7 @@
/**
* Makes and returns a mutable copy of this instance.
*
- * @return non-null; the copy
+ * @return {@code non-null;} the copy
*/
public ExecutionStack copy() {
ExecutionStack result = new ExecutionStack(stack.length);
@@ -69,7 +69,7 @@
* Annotates (adds context to) the given exception with information
* about this instance.
*
- * @param ex non-null; the exception to annotate
+ * @param ex {@code non-null;} the exception to annotate
*/
public void annotate(ExceptionWithContext ex) {
int limit = stackPtr - 1;
@@ -86,7 +86,7 @@
* Replaces all the occurrences of the given uninitialized type in
* this stack with its initialized equivalent.
*
- * @param type non-null; type to replace
+ * @param type {@code non-null;} type to replace
*/
public void makeInitialized(Type type) {
if (stackPtr == 0) {
@@ -108,7 +108,7 @@
/**
* Gets the maximum stack size for this instance.
*
- * @return >= 0; the max stack size
+ * @return {@code >= 0;} the max stack size
*/
public int getMaxStack() {
return stack.length;
@@ -117,7 +117,7 @@
/**
* Gets the current stack size.
*
- * @return >= 0, < getMaxStack(); the current stack size
+ * @return {@code >= 0, < getMaxStack();} the current stack size
*/
public int size() {
return stackPtr;
@@ -139,7 +139,7 @@
/**
* Pushes a value of the given type onto the stack.
*
- * @param type non-null; type of the value
+ * @param type {@code non-null;} type of the value
* @throws SimException thrown if there is insufficient room on the
* stack for the value
*/
@@ -171,14 +171,14 @@
}
/**
- * Peeks at the <code>n</code>th element down from the top of the stack.
- * <code>n == 0</code> means to peek at the top of the stack. Note that
- * this will return <code>null</code> if the indicated element is the
+ * Peeks at the {@code n}th element down from the top of the stack.
+ * {@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 >= 0; which element to peek at
- * @return null-ok; the type of value stored at that element
- * @throws SimException thrown if <code>n >= size()</code>
+ * @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()}
*/
public TypeBearer peek(int n) {
if (n < 0) {
@@ -193,10 +193,10 @@
}
/**
- * Peeks at the <code>n</code>th element down from the top of the
+ * Peeks at the {@code n}th element down from the top of the
* 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()</code>.
+ * for {@code peek(n).getType()}.
*
* @see #peek
*/
@@ -207,7 +207,7 @@
/**
* Pops the top element off of the stack.
*
- * @return non-null; the type formerly on the top of the stack
+ * @return {@code non-null;} the type formerly on the top of the stack
* @throws SimException thrown if the stack is empty
*/
public TypeBearer pop() {
@@ -227,10 +227,10 @@
* the following restriction on its behavior: You may only replace
* values with other values of the same category.
*
- * @param n >= 0; which element to change, where <code>0</code> is
+ * @param n {@code >= 0;} which element to change, where {@code 0} is
* the top element of the stack
- * @param type non-null; type of the new value
- * @throws SimException thrown if <code>n >= size()</code> or
+ * @param type {@code non-null;} type of the new value
+ * @throws SimException thrown if {@code n >= size()} or
* the action is otherwise prohibited
*/
public void change(int n, TypeBearer type) {
@@ -262,8 +262,8 @@
* returned. See {@link Merger#mergeStack(ExecutionStack,ExecutionStack)
* Merger.mergeStack()}
*
- * @param other non-null; a stack to merge with
- * @return non-null; the result of the merge
+ * @param other {@code non-null;} a stack to merge with
+ * @return {@code non-null;} the result of the merge
*/
public ExecutionStack merge(ExecutionStack other) {
try {
@@ -279,11 +279,11 @@
/**
* Gets the string form for a stack element. This is the same as
- * <code>toString()</code> except that <code>null</code> is converted
- * to <code>"<invalid>"</code>.
+ * {@code toString()} except that {@code null} is converted
+ * to {@code "<invalid>"}.
*
- * @param type null-ok; the stack element
- * @return non-null; the string form
+ * @param type {@code null-ok;} the stack element
+ * @return {@code non-null;} the string form
*/
private static String stackElementString(TypeBearer type) {
if (type == null) {
@@ -296,7 +296,7 @@
/**
* Throws a properly-formatted exception.
*
- * @param msg non-null; useful message
+ * @param msg {@code non-null;} useful message
* @return never (keeps compiler happy)
*/
private static TypeBearer throwSimException(String msg) {
diff --git a/dx/src/com/android/dx/cf/code/Frame.java b/dx/src/com/android/dx/cf/code/Frame.java
index a74d142..f345335 100644
--- a/dx/src/com/android/dx/cf/code/Frame.java
+++ b/dx/src/com/android/dx/cf/code/Frame.java
@@ -29,20 +29,20 @@
* results" area.
*/
public final class Frame {
- /** non-null; the locals */
+ /** {@code non-null;} the locals */
private final LocalsArray locals;
- /** non-null; the stack */
+ /** {@code non-null;} the stack */
private final ExecutionStack stack;
- /** null-ok; stack of labels of subroutines that this block is nested in */
+ /** {@code null-ok;} stack of labels of subroutines that this block is nested in */
private final IntList subroutines;
/**
* Constructs an instance.
*
- * @param locals non-null; the locals array to use
- * @param stack non-null; the execution stack to use
+ * @param locals {@code non-null;} the locals array to use
+ * @param stack {@code non-null;} the execution stack to use
*/
private Frame(LocalsArray locals, ExecutionStack stack) {
this(locals, stack, IntList.EMPTY);
@@ -51,9 +51,9 @@
/**
* Constructs an instance.
*
- * @param locals non-null; the locals array to use
- * @param stack non-null; the execution stack to use
- * @param subroutines non-null; list of subroutine start labels for
+ * @param locals {@code non-null;} the locals array to use
+ * @param stack {@code non-null;} the execution stack to use
+ * @param subroutines {@code non-null;} list of subroutine start labels for
* subroutines this frame is nested in
*/
private Frame(LocalsArray locals,
@@ -75,12 +75,12 @@
/**
* Constructs an instance. The locals array initially consists of
- * all-uninitialized values (represented as <code>null</code>s) and
+ * all-uninitialized values (represented as {@code null}s) and
* the stack starts out empty.
*
- * @param maxLocals >= 0; the maximum number of locals this instance
+ * @param maxLocals {@code >= 0;} the maximum number of locals this instance
* can refer to
- * @param maxStack >= 0; the maximum size of the stack for this
+ * @param maxStack {@code >= 0;} the maximum size of the stack for this
* instance
*/
public Frame(int maxLocals, int maxStack) {
@@ -92,7 +92,7 @@
* contains copies of the locals and stack (that is, it doesn't
* share them with the original).
*
- * @return non-null; the copy
+ * @return {@code non-null;} the copy
*/
public Frame copy() {
return new Frame(locals.copy(), stack.copy(), subroutines);
@@ -111,7 +111,7 @@
* Replaces all the occurrences of the given uninitialized type in
* this frame with its initialized equivalent.
*
- * @param type non-null; type to replace
+ * @param type {@code non-null;} type to replace
*/
public void makeInitialized(Type type) {
locals.makeInitialized(type);
@@ -121,7 +121,7 @@
/**
* Gets the locals array for this instance.
*
- * @return non-null; the locals array
+ * @return {@code non-null;} the locals array
*/
public LocalsArray getLocals() {
return locals;
@@ -130,7 +130,7 @@
/**
* Gets the execution stack for this instance.
*
- * @return non-null; the execution stack
+ * @return {@code non-null;} the execution stack
*/
public ExecutionStack getStack() {
return stack;
@@ -143,7 +143,7 @@
* list is ordered such that the deepest nesting (the actual subroutine
* this block is in) is the last label in the list.
*
- * @return non-null; list as noted above
+ * @return {@code non-null;} list as noted above
*/
public IntList getSubroutines() {
return subroutines;
@@ -171,10 +171,10 @@
* be used when returning from a subroutine. The stack state of all
* subroutine invocations is identical, but the locals state may differ.
*
- * @param startLabel >=0; The label of the returning subroutine's
+ * @param startLabel {@code >=0;} The label of the returning subroutine's
* start block
- * @param subLabel >=0; A calling label of a subroutine
- * @return null-ok; an appropriatly-constructed instance, or null
+ * @param subLabel {@code >=0;} A calling label of a subroutine
+ * @return {@code null-ok;} an appropriatly-constructed instance, or null
* if label is not in the set
*/
public Frame subFrameForLabel(int startLabel, int subLabel) {
@@ -206,8 +206,8 @@
* Merges two frames. If the merged result is the same as this frame,
* then this instance is returned.
*
- * @param other non-null; another frame
- * @return non-null; the result of merging the two frames
+ * @param other {@code non-null;} another frame
+ * @return {@code non-null;} the result of merging the two frames
*/
public Frame mergeWith(Frame other) {
LocalsArray resultLocals;
@@ -237,7 +237,7 @@
*
* @param otherSubroutines label list of subroutine start blocks, from
* least-nested to most-nested.
- * @return non-null; merged subroutine nest list as described above
+ * @return {@code non-null;} merged subroutine nest list as described above
*/
private IntList mergeSubroutineLists(IntList otherSubroutines) {
if (subroutines.equals(otherSubroutines)) {
@@ -265,10 +265,10 @@
* need to be trimmed of all OneLocalsArray elements that relevent to
* the subroutine that is returning.
*
- * @param locals non-null; LocalsArray from before a merge
- * @param subroutines non-null; a label list of subroutine start blocks
+ * @param locals {@code non-null;} LocalsArray from before a merge
+ * @param subroutines {@code non-null;} a label list of subroutine start blocks
* representing the subroutine nesting of the block being merged into.
- * @return non-null; locals set appropriate for merge
+ * @return {@code non-null;} locals set appropriate for merge
*/
private static LocalsArray adjustLocalsForSubroutines(
LocalsArray locals, IntList subroutines) {
@@ -301,13 +301,13 @@
/**
* Merges this frame with the frame of a subroutine caller at
- * <code>predLabel</code>. Only called on the frame at the first
+ * {@code predLabel}. Only called on the frame at the first
* block of a subroutine.
*
- * @param other non-null; another frame
+ * @param other {@code non-null;} another frame
* @param subLabel label of subroutine start block
* @param predLabel label of calling block
- * @return non-null; the result of merging the two frames
+ * @return {@code non-null;} the result of merging the two frames
*/
public Frame mergeWithSubroutineCaller(Frame other, int subLabel,
int predLabel) {
@@ -374,7 +374,7 @@
* subroutine calls return.
*
* @param subLabel label of subroutine start block
- * @param callerLabel >=0 label of the caller block where this frame
+ * @param callerLabel {@code >=0;} label of the caller block where this frame
* came from.
* @return a new instance to begin a called subroutine.
*/
@@ -406,7 +406,7 @@
* Annotates (adds context to) the given exception with information
* about this frame.
*
- * @param ex non-null; the exception to annotate
+ * @param ex {@code non-null;} the exception to annotate
*/
public void annotate(ExceptionWithContext ex) {
locals.annotate(ex);
diff --git a/dx/src/com/android/dx/cf/code/LineNumberList.java b/dx/src/com/android/dx/cf/code/LineNumberList.java
index 35875b0..7af3f4e 100644
--- a/dx/src/com/android/dx/cf/code/LineNumberList.java
+++ b/dx/src/com/android/dx/cf/code/LineNumberList.java
@@ -20,19 +20,19 @@
/**
* List of "line number" entries, which are the contents of
- * <code>LineNumberTable</code> attributes.
+ * {@code LineNumberTable} attributes.
*/
public final class LineNumberList extends FixedSizeList {
- /** non-null; zero-size instance */
+ /** {@code non-null;} zero-size instance */
public static final LineNumberList EMPTY = new LineNumberList(0);
/**
* Returns an instance which is the concatenation of the two given
* instances.
*
- * @param list1 non-null; first instance
- * @param list2 non-null; second instance
- * @return non-null; combined instance
+ * @param list1 {@code non-null;} first instance
+ * @param list2 {@code non-null;} second instance
+ * @return {@code non-null;} combined instance
*/
public static LineNumberList concat(LineNumberList list1,
LineNumberList list2) {
@@ -68,8 +68,8 @@
/**
* Gets the indicated item.
*
- * @param n >= 0; which item
- * @return null-ok; the indicated item
+ * @param n {@code >= 0;} which item
+ * @return {@code null-ok;} the indicated item
*/
public Item get(int n) {
return (Item) get0(n);
@@ -78,8 +78,8 @@
/**
* Sets the item at the given index.
*
- * @param n >= 0, < size(); which element
- * @param item non-null; the item
+ * @param n {@code >= 0, < size();} which element
+ * @param item {@code non-null;} the item
*/
public void set(int n, Item item) {
if (item == null) {
@@ -92,9 +92,9 @@
/**
* Sets the item at the given index.
*
- * @param n >= 0, < size(); which element
- * @param startPc >= 0; start pc of this item
- * @param lineNumber >= 0; corresponding line number
+ * @param n {@code >= 0, < size();} which element
+ * @param startPc {@code >= 0;} start pc of this item
+ * @param lineNumber {@code >= 0;} corresponding line number
*/
public void set(int n, int startPc, int lineNumber) {
set0(n, new Item(startPc, lineNumber));
@@ -103,8 +103,8 @@
/**
* Gets the line number associated with the given address.
*
- * @param pc >= 0; the address to look up
- * @return >= -1; the associated line number, or <code>-1</code> if
+ * @param pc {@code >= 0;} the address to look up
+ * @return {@code >= -1;} the associated line number, or {@code -1} if
* none is known
*/
public int pcToLine(int pc) {
@@ -138,17 +138,17 @@
* Item in a line number table.
*/
public static class Item {
- /** >= 0; start pc of this item */
+ /** {@code >= 0;} start pc of this item */
private final int startPc;
- /** >= 0; corresponding line number */
+ /** {@code >= 0;} corresponding line number */
private final int lineNumber;
/**
* Constructs an instance.
*
- * @param startPc >= 0; start pc of this item
- * @param lineNumber >= 0; corresponding line number
+ * @param startPc {@code >= 0;} start pc of this item
+ * @param lineNumber {@code >= 0;} corresponding line number
*/
public Item(int startPc, int lineNumber) {
if (startPc < 0) {
diff --git a/dx/src/com/android/dx/cf/code/LocalVariableList.java b/dx/src/com/android/dx/cf/code/LocalVariableList.java
index 1087603..8f49a33 100644
--- a/dx/src/com/android/dx/cf/code/LocalVariableList.java
+++ b/dx/src/com/android/dx/cf/code/LocalVariableList.java
@@ -23,20 +23,20 @@
/**
* List of "local variable" entries, which are the contents of
- * <code>LocalVariableTable</code> and <code>LocalVariableTypeTable</code>
+ * {@code LocalVariableTable} and {@code LocalVariableTypeTable}
* attributes, as well as combinations of the two.
*/
public final class LocalVariableList extends FixedSizeList {
- /** non-null; zero-size instance */
+ /** {@code non-null;} zero-size instance */
public static final LocalVariableList EMPTY = new LocalVariableList(0);
/**
* Returns an instance which is the concatenation of the two given
* instances. The result is immutable.
*
- * @param list1 non-null; first instance
- * @param list2 non-null; second instance
- * @return non-null; combined instance
+ * @param list1 {@code non-null;} first instance
+ * @param list2 {@code non-null;} second instance
+ * @return {@code non-null;} combined instance
*/
public static LocalVariableList concat(LocalVariableList list1,
LocalVariableList list2) {
@@ -70,14 +70,13 @@
* element in the signature list gets augmented with the
* corresponding signature. The result is immutable.
*
- * @param descriptorList non-null; list with descriptors
- * @param signatureList non-null; list with signatures
- * @return non-null; the merged result
+ * @param descriptorList {@code non-null;} list with descriptors
+ * @param signatureList {@code non-null;} list with signatures
+ * @return {@code non-null;} the merged result
*/
public static LocalVariableList mergeDescriptorsAndSignatures(
LocalVariableList descriptorList,
LocalVariableList signatureList) {
- int signatureSize = signatureList.size();
int descriptorSize = descriptorList.size();
LocalVariableList result = new LocalVariableList(descriptorSize);
@@ -107,8 +106,8 @@
/**
* Gets the indicated item.
*
- * @param n >= 0; which item
- * @return null-ok; the indicated item
+ * @param n {@code >= 0;} which item
+ * @return {@code null-ok;} the indicated item
*/
public Item get(int n) {
return (Item) get0(n);
@@ -117,8 +116,8 @@
/**
* Sets the item at the given index.
*
- * @param n >= 0, < size(); which element
- * @param item non-null; the item
+ * @param n {@code >= 0, < size();} which element
+ * @param item {@code non-null;} the item
*/
public void set(int n, Item item) {
if (item == null) {
@@ -131,17 +130,17 @@
/**
* Sets the item at the given index.
*
- * <p><b>Note:</b> At least one of <code>descriptor</code> or
- * <code>signature</code> must be passed as non-null.</p>
+ * <p><b>Note:</b> At least one of {@code descriptor} or
+ * {@code signature} must be passed as non-null.</p>
*
- * @param n >= 0, < size(); which element
- * @param startPc >= 0; the start pc of this variable's scope
- * @param length >= 0; the length (in bytecodes) of this variable's
+ * @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
* scope
- * @param name non-null; the variable's name
- * @param descriptor null-ok; the variable's type descriptor
- * @param signature null-ok; the variable's type signature
- * @param index >= 0; the variable's local index
+ * @param name {@code non-null;} the variable's name
+ * @param descriptor {@code null-ok;} the variable's type descriptor
+ * @param signature {@code null-ok;} the variable's type signature
+ * @param index {@code >= 0;} the variable's local index
*/
public void set(int n, int startPc, int length, CstUtf8 name,
CstUtf8 descriptor, CstUtf8 signature, int index) {
@@ -153,9 +152,9 @@
* the given {@link com.android.dx.cf.code.LocalVariableList.Item}
* in all respects but the type descriptor and signature, if any.
*
- * @param item non-null; local variable information to match
- * @return null-ok; the corresponding local variable information stored
- * in this instance, or <code>null</code> if there is no matching
+ * @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
* information
*/
public Item itemToLocal(Item item) {
@@ -178,10 +177,10 @@
* variable's start point is listed as the address of the instruction
* <i>just past</i> the one that sets the variable.
*
- * @param pc >= 0; the address to look up
- * @param index >= 0; the local variable index
- * @return null-ok; the associated local variable information, or
- * <code>null</code> if none is known
+ * @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
+ * {@code null} if none is known
*/
public Item pcAndIndexToLocal(int pc, int index) {
int sz = size();
@@ -201,37 +200,37 @@
* Item in a local variable table.
*/
public static class Item {
- /** >= 0; the start pc of this variable's scope */
+ /** {@code >= 0;} the start pc of this variable's scope */
private final int startPc;
- /** >= 0; the length (in bytecodes) of this variable's scope */
+ /** {@code >= 0;} the length (in bytecodes) of this variable's scope */
private final int length;
- /** non-null; the variable's name */
+ /** {@code non-null;} the variable's name */
private final CstUtf8 name;
- /** null-ok; the variable's type descriptor */
+ /** {@code null-ok;} the variable's type descriptor */
private final CstUtf8 descriptor;
- /** null-ok; the variable's type signature */
+ /** {@code null-ok;} the variable's type signature */
private final CstUtf8 signature;
- /** >= 0; the variable's local index */
+ /** {@code >= 0;} the variable's local index */
private final int index;
/**
* Constructs an instance.
*
- * <p><b>Note:</b> At least one of <code>descriptor</code> or
- * <code>signature</code> must be passed as non-null.</p>
+ * <p><b>Note:</b> At least one of {@code descriptor} or
+ * {@code signature} must be passed as non-null.</p>
*
- * @param startPc >= 0; the start pc of this variable's scope
- * @param length >= 0; the length (in bytecodes) of this variable's
+ * @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
- * @param name non-null; the variable's name
- * @param descriptor null-ok; the variable's type descriptor
- * @param signature null-ok; the variable's type signature
- * @param index >= 0; the variable's local index
+ * @param name {@code non-null;} the variable's name
+ * @param descriptor {@code null-ok;} the variable's type descriptor
+ * @param signature {@code null-ok;} the variable's type signature
+ * @param index {@code >= 0;} the variable's local index
*/
public Item(int startPc, int length, CstUtf8 name,
CstUtf8 descriptor, CstUtf8 signature, int index) {
@@ -267,7 +266,7 @@
/**
* Gets the start pc of this variable's scope.
*
- * @return >= 0; the start pc of this variable's scope
+ * @return {@code >= 0;} the start pc of this variable's scope
*/
public int getStartPc() {
return startPc;
@@ -276,7 +275,7 @@
/**
* Gets the length (in bytecodes) of this variable's scope.
*
- * @return >= 0; the length (in bytecodes) of this variable's scope
+ * @return {@code >= 0;} the length (in bytecodes) of this variable's scope
*/
public int getLength() {
return length;
@@ -285,7 +284,7 @@
/**
* Gets the variable's type descriptor.
*
- * @return null-ok; the variable's type descriptor
+ * @return {@code null-ok;} the variable's type descriptor
*/
public CstUtf8 getDescriptor() {
return descriptor;
@@ -294,7 +293,7 @@
/**
* Gets the variable's LocalItem, a (name, signature) tuple
*
- * @return null-ok; the variable's type descriptor
+ * @return {@code null-ok;} the variable's type descriptor
*/
public LocalItem getLocalItem() {
return LocalItem.make(name, signature);
@@ -304,7 +303,7 @@
* Gets the variable's type signature. Private because if you need this,
* you want getLocalItem() instead.
*
- * @return null-ok; the variable's type signature
+ * @return {@code null-ok;} the variable's type signature
*/
private CstUtf8 getSignature() {
return signature;
@@ -313,7 +312,7 @@
/**
* Gets the variable's local index.
*
- * @return >= 0; the variable's local index
+ * @return {@code >= 0;} the variable's local index
*/
public int getIndex() {
return index;
@@ -321,9 +320,9 @@
/**
* Gets the variable's type descriptor. This is a convenient shorthand
- * for <code>Type.intern(getDescriptor().getString())</code>.
+ * for {@code Type.intern(getDescriptor().getString())}.
*
- * @return non-null; the variable's type
+ * @return {@code non-null;} the variable's type
*/
public Type getType() {
return Type.intern(descriptor.getString());
@@ -333,8 +332,8 @@
* Constructs and returns an instance which is identical to this
* one, except that the signature is changed to the given value.
*
- * @param newSignature non-null; the new signature
- * @return non-null; an appropriately-constructed instance
+ * @param newSignature {@code non-null;} the new signature
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public Item withSignature(CstUtf8 newSignature) {
return new Item(startPc, length, name, descriptor, newSignature,
@@ -345,10 +344,10 @@
* Gets whether this instance matches (describes) the given
* address and index.
*
- * @param pc >= 0; the address in question
- * @param index >= 0; the local variable index in question
- * @return <code>true</code> iff this instance matches <code>pc</code>
- * and <code>index</code>
+ * @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}
+ * and {@code index}
*/
public boolean matchesPcAndIndex(int pc, int index) {
return (index == this.index) &&
@@ -361,8 +360,8 @@
* other instance exactly in all fields except type descriptor and
* type signature.
*
- * @param other non-null; the instance to compare to
- * @return <code>true</code> iff this instance matches
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code true} iff this instance matches
*/
public boolean matchesAllButType(Item other) {
return (startPc == other.startPc)
diff --git a/dx/src/com/android/dx/cf/code/LocalsArray.java b/dx/src/com/android/dx/cf/code/LocalsArray.java
index 1c324ca..b2c2689 100644
--- a/dx/src/com/android/dx/cf/code/LocalsArray.java
+++ b/dx/src/com/android/dx/cf/code/LocalsArray.java
@@ -36,7 +36,7 @@
/**
* Constructs an instance, explicitly indicating the mutability.
*
- * @param mutable <code>true</code> if this instance is mutable
+ * @param mutable {@code true} if this instance is mutable
*/
protected LocalsArray(boolean mutable) {
super(mutable);
@@ -45,7 +45,7 @@
/**
* Makes and returns a mutable copy of this instance.
*
- * @return non-null; the copy
+ * @return {@code non-null;} the copy
*/
public abstract LocalsArray copy();
@@ -53,7 +53,7 @@
* Annotates (adds context to) the given exception with information
* about this instance.
*
- * @param ex non-null; the exception to annotate
+ * @param ex {@code non-null;} the exception to annotate
*/
public abstract void annotate(ExceptionWithContext ex);
@@ -61,7 +61,7 @@
* Replaces all the occurrences of the given uninitialized type in
* this array with its initialized equivalent.
*
- * @param type non-null; type to replace
+ * @param type {@code non-null;} type to replace
*/
public abstract void makeInitialized(Type type);
@@ -71,16 +71,17 @@
* @return the max locals
*/
public abstract int getMaxLocals();
+
/**
* Sets the type stored at the given local index. If the given type
* is category-2, then (a) the index must be at least two less than
- * <code>getMaxLocals()</code> and (b) the next index gets invalidated
+ * {@link #getMaxLocals} and (b) the next index gets invalidated
* 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 >= 0, < getMaxLocals(); which local
- * @param type non-null; new type for the local at <code>idx</code>
+ * @param idx {@code >= 0, < getMaxLocals();} which local
+ * @param type {@code non-null;} new type for the local at {@code idx}
*/
public abstract void set(int idx, TypeBearer type);
@@ -88,25 +89,25 @@
* Sets the type for the local indicated by the given register spec
* to that register spec (which includes type and optional name
* information). This is identical to calling
- * <code>set(spec.getReg(), spec)</code>.
+ * {@code set(spec.getReg(), spec)}.
*
- * @param spec non-null; register spec to use as the basis for the update
+ * @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 >= 0, < getMaxLocals(); which local
+ * @param idx {@code >= 0, < getMaxLocals();} which local
*/
public abstract void invalidate(int idx);
/**
- * Gets the type stored at the given local index, or <code>null</code>
+ * Gets the type stored at the given local index, or {@code null}
* if the given local is uninitialized / invalid.
*
- * @param idx >= 0, < getMaxLocals(); which local
- * @return null-ok; the type of value stored in that local
+ * @param idx {@code >= 0, < getMaxLocals();} which local
+ * @return {@code null-ok;} the type of value stored in that local
*/
public abstract TypeBearer getOrNull(int idx);
@@ -115,9 +116,9 @@
* the given local contains a valid type (though it is allowed to
* be an uninitialized instance).
*
- * @param idx >= 0, < getMaxLocals(); which local
- * @return non-null; the type of value stored in that local
- * @throws SimException thrown if <code>idx</code> is valid, but
+ * @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
* the contents are invalid
*/
public abstract TypeBearer get(int idx);
@@ -126,9 +127,9 @@
* Gets the type stored at the given local index, which is expected
* to be an initialized category-1 value.
*
- * @param idx >= 0, < getMaxLocals(); which local
- * @return non-null; the type of value stored in that local
- * @throws SimException thrown if <code>idx</code> is valid, but
+ * @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
* one of the following holds: (a) the local is invalid; (b) the local
* contains an uninitialized instance; (c) the local contains a
* category-2 value
@@ -139,39 +140,39 @@
* Gets the type stored at the given local index, which is expected
* to be a category-2 value.
*
- * @param idx >= 0, < getMaxLocals(); which local
- * @return non-null; the type of value stored in that local
- * @throws SimException thrown if <code>idx</code> is valid, but
+ * @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
* one of the following holds: (a) the local is invalid; (b) the local
* contains a category-1 value
*/
public abstract TypeBearer getCategory2(int idx);
/**
- * Merges this instance with <code>other</code>. If the merged result is
+ * Merges this instance with {@code other}. If the merged result is
* the same as this instance, then this is returned (not a copy).
*
- * @param other non-null; another LocalsArray
- * @return non-null; the merge result, a new instance or this
+ * @param other {@code non-null;} another LocalsArray
+ * @return {@code non-null;} the merge result, a new instance or this
*/
public abstract LocalsArray merge(LocalsArray other);
/**
- * Merges this instance with a <code>LocalsSet</code> from a subroutine
+ * Merges this instance with a {@code LocalsSet} from a subroutine
* caller. To be used when merging in the first block of a subroutine.
*
- * @param other other non-null; another LocalsArray. The final locals
+ * @param other {@code other non-null;} another LocalsArray. The final locals
* state of a subroutine caller.
* @param predLabel the label of the subroutine caller block.
- * @return non-null; the merge result, a new instance or this
+ * @return {@code non-null;} the merge result, a new instance or this
*/
public abstract LocalsArraySet mergeWithSubroutineCaller
(LocalsArray other, int predLabel);
/**
* Gets the locals set appropriate for the current execution context.
- * That is, if this is a <code>OneLocalsArray</code> instance, then return
- * <code>this</code>, otherwise return <code>LocalsArraySet</code>'s
+ * That is, if this is a {@code OneLocalsArray} instance, then return
+ * {@code this}, otherwise return {@code LocalsArraySet}'s
* primary.
*
* @return locals for this execution context.
diff --git a/dx/src/com/android/dx/cf/code/LocalsArraySet.java b/dx/src/com/android/dx/cf/code/LocalsArraySet.java
index 9e24da9..fa2acbe 100644
--- a/dx/src/com/android/dx/cf/code/LocalsArraySet.java
+++ b/dx/src/com/android/dx/cf/code/LocalsArraySet.java
@@ -51,9 +51,9 @@
/**
* Constructs an instance. The locals array initially consists of
- * all-uninitialized values (represented as <code>null</code>s).
+ * all-uninitialized values (represented as {@code null}s).
*
- * @param maxLocals >= 0; the maximum number of locals this instance
+ * @param maxLocals {@code >= 0;} the maximum number of locals this instance
* can refer to
*/
public LocalsArraySet(int maxLocals) {
@@ -65,8 +65,8 @@
/**
* Constructs an instance with the specified primary and secondaries set.
*
- * @param primary non-null; primary locals to use
- * @param secondaries non-null; secondaries set, indexed by subroutine
+ * @param primary {@code non-null;} primary locals to use
+ * @param secondaries {@code non-null;} secondaries set, indexed by subroutine
* caller label.
*/
public LocalsArraySet(OneLocalsArray primary,
@@ -80,7 +80,7 @@
/**
* Constructs an instance which is a copy of another.
*
- * @param toCopy non-null; instance to copy.
+ * @param toCopy {@code non-null;} instance to copy.
*/
private LocalsArraySet(LocalsArraySet toCopy) {
super(toCopy.getMaxLocals() > 0);
@@ -89,7 +89,7 @@
secondaries = new ArrayList(toCopy.secondaries.size());
int sz = toCopy.secondaries.size();
- for(int i = 0; i < sz; i++) {
+ for (int i = 0; i < sz; i++) {
LocalsArray la = toCopy.secondaries.get(i);
if (la == null) {
@@ -106,7 +106,7 @@
public void setImmutable() {
primary.setImmutable();
- for (LocalsArray la: secondaries) {
+ for (LocalsArray la : secondaries) {
if (la != null) {
la.setImmutable();
}
@@ -127,7 +127,7 @@
primary.annotate(ex);
int sz = secondaries.size();
- for(int label = 0; label < sz; label++) {
+ for (int label = 0; label < sz; label++) {
LocalsArray la = secondaries.get(label);
if (la != null) {
@@ -149,7 +149,7 @@
sb.append('\n');
int sz = secondaries.size();
- for(int label = 0; label < sz; label++) {
+ for (int label = 0; label < sz; label++) {
LocalsArray la = secondaries.get(label);
if (la != null) {
@@ -178,7 +178,7 @@
primary.makeInitialized(type);
- for (LocalsArray la: secondaries) {
+ for (LocalsArray la : secondaries) {
if (la != null) {
la.makeInitialized(type);
}
@@ -198,7 +198,7 @@
primary.set(idx, type);
- for (LocalsArray la: secondaries) {
+ for (LocalsArray la : secondaries) {
if (la != null) {
la.set(idx, type);
}
@@ -218,7 +218,7 @@
primary.invalidate(idx);
- for (LocalsArray la: secondaries) {
+ for (LocalsArray la : secondaries) {
if (la != null) {
la.invalidate(idx);
}
@@ -250,10 +250,10 @@
}
/**
- * Merges this set with another <code>LocalsArraySet</code> instance.
+ * Merges this set with another {@code LocalsArraySet} instance.
*
- * @param other non-null; to merge
- * @return non-null; this instance if merge was a no-op, or
+ * @param other {@code non-null;} to merge
+ * @return {@code non-null;} this instance if merge was a no-op, or
* new merged instance.
*/
private LocalsArraySet mergeWithSet(LocalsArraySet other) {
@@ -301,10 +301,10 @@
}
/**
- * Merges this set with a <code>OneLocalsArray</code> instance.
+ * Merges this set with a {@code OneLocalsArray} instance.
*
- * @param other non-null; to merge
- * @return non-null; this instance if merge was a no-op, or
+ * @param other {@code non-null;} to merge
+ * @return {@code non-null;} this instance if merge was a no-op, or
* new merged instance.
*/
private LocalsArraySet mergeWithOne(OneLocalsArray other) {
@@ -365,11 +365,11 @@
}
/**
- * Gets the <code>LocalsArray</code> instance for a specified subroutine
+ * Gets the {@code LocalsArray} instance for a specified subroutine
* caller label, or null if label has no locals associated with it.
*
- * @param label >=0 subroutine caller label
- * @return null-ok; locals if available.
+ * @param label {@code >= 0;} subroutine caller label
+ * @return {@code null-ok;} locals if available.
*/
private LocalsArray getSecondaryForLabel(int label) {
if (label >= secondaries.size()) {
@@ -445,8 +445,8 @@
* Returns a LocalsArray instance representing the locals state that should
* be used when returning to a subroutine caller.
*
- * @param subLabel >= 0; A calling label of a subroutine
- * @return null-ok; an instance for this subroutine, or null if subroutine
+ * @param subLabel {@code >= 0;} A calling label of a subroutine
+ * @return {@code null-ok;} an instance for this subroutine, or null if subroutine
* is not in this set.
*/
public LocalsArray subArrayForLabel(int subLabel) {
diff --git a/dx/src/com/android/dx/cf/code/Machine.java b/dx/src/com/android/dx/cf/code/Machine.java
index 517a10d..aff50b2 100644
--- a/dx/src/com/android/dx/cf/code/Machine.java
+++ b/dx/src/com/android/dx/cf/code/Machine.java
@@ -32,9 +32,9 @@
/**
* Gets the effective prototype of the method that this instance is
* being used for. The <i>effective</i> prototype includes an initial
- * <code>this</code> argument for instance methods.
+ * {@code this} argument for instance methods.
*
- * @return non-null; the method prototype
+ * @return {@code non-null;} the method prototype
*/
public Prototype getPrototype();
@@ -48,21 +48,21 @@
* and store them in the arguments area, indicating that there are now
* that many arguments. Also, clear the auxiliary arguments.
*
- * @param frame non-null; frame to operate on
- * @param count >= 0; number of values to pop
+ * @param frame {@code non-null;} frame to operate on
+ * @param count {@code >= 0;} number of values to pop
*/
public void popArgs(Frame frame, int count);
/**
* Pops values from the stack of the types indicated by the given
- * <code>Prototype</code> (popped in reverse of the argument
+ * {@code Prototype} (popped in reverse of the argument
* order, so the first prototype argument type is for the deepest
* element of the stack), and store them in the arguments area,
* indicating that there are now that many arguments. Also, clear
* the auxiliary arguments.
*
- * @param frame non-null; frame to operate on
- * @param prototype non-null; prototype indicating arguments to pop
+ * @param frame {@code non-null;} frame to operate on
+ * @param prototype {@code non-null;} prototype indicating arguments to pop
*/
public void popArgs(Frame frame, Prototype prototype);
@@ -71,8 +71,8 @@
* in the arguments area, indicating that there are now that many
* arguments. Also, clear the auxiliary arguments.
*
- * @param frame non-null; frame to operate on
- * @param type non-null; type of the argument
+ * @param frame {@code non-null;} frame to operate on
+ * @param type {@code non-null;} type of the argument
*/
public void popArgs(Frame frame, Type type);
@@ -83,9 +83,9 @@
* area, indicating that there are now that many arguments. Also,
* clear the auxiliary arguments.
*
- * @param frame non-null; frame to operate on
- * @param type1 non-null; type of the first argument
- * @param type2 non-null; type of the second argument
+ * @param frame {@code non-null;} frame to operate on
+ * @param type1 {@code non-null;} type of the first argument
+ * @param type2 {@code non-null;} type of the second argument
*/
public void popArgs(Frame frame, Type type1, Type type2);
@@ -96,10 +96,10 @@
* area, indicating that there are now that many arguments. Also,
* clear the auxiliary arguments.
*
- * @param frame non-null; frame to operate on
- * @param type1 non-null; type of the first argument
- * @param type2 non-null; type of the second argument
- * @param type3 non-null; type of the third argument
+ * @param frame {@code non-null;} frame to operate on
+ * @param type1 {@code non-null;} type of the first argument
+ * @param type2 {@code non-null;} type of the second argument
+ * @param type3 {@code non-null;} type of the third argument
*/
public void popArgs(Frame frame, Type type1, Type type2, Type type3);
@@ -107,8 +107,8 @@
* Loads the local variable with the given index as the sole argument in
* the arguments area. Also, clear the auxiliary arguments.
*
- * @param frame non-null; frame to operate on
- * @param idx >= 0; the local variable index
+ * @param frame {@code non-null;} frame to operate on
+ * @param idx {@code >= 0;} the local variable index
*/
public void localArg(Frame frame, int idx);
@@ -116,28 +116,28 @@
* Indicates that the salient type of this operation is as
* given. This differentiates between, for example, the various
* arithmetic opcodes, which, by the time they hit a
- * <code>Machine</code> are collapsed to the <code>int</code>
+ * {@code Machine} are collapsed to the {@code int}
* variant. (See {@link BytecodeArray#parseInstruction} for
* details.)
*
- * @param type non-null; the salient type of the upcoming operation
+ * @param type {@code non-null;} the salient type of the upcoming operation
*/
public void auxType(Type type);
/**
* Indicates that there is an auxiliary (inline, not stack)
- * argument of type <code>int</code>, with the given value.
+ * argument of type {@code int}, with the given value.
*
* <p><b>Note:</b> Perhaps unintuitively, the stack manipulation
- * ops (e.g., <code>dup</code> and <code>swap</code>) use this to
+ * ops (e.g., {@code dup} and {@code swap}) use this to
* indicate the result stack pattern with a straightforward hex
* encoding of the push order starting with least-significant
* nibbles getting pushed first). For example, an all-category-1
- * <code>dup2_x1</code> sets this to <code>0x12312</code>, and the
+ * {@code dup2_x1} sets this to {@code 0x12312}, and the
* other form of that op sets this to
- * <code>0x121</code>.</p>
+ * {@code 0x121}.</p>
*
- * <p><b>Also Note:</b> For <code>switch*</code> instructions, this is
+ * <p><b>Also Note:</b> For {@code switch*} instructions, this is
* used to indicate the padding value (which is only useful for
* verification).</p>
*
@@ -149,10 +149,10 @@
* Indicates that there is an auxiliary (inline, not stack) object
* argument, with the value based on the given constant.
*
- * <p><b>Note:</b> Some opcodes use both <code>int</code> and
+ * <p><b>Note:</b> Some opcodes use both {@code int} and
* constant auxiliary arguments.</p>
*
- * @param cst non-null; the constant containing / referencing
+ * @param cst {@code non-null;} the constant containing / referencing
* the value
*/
public void auxCstArg(Constant cst);
@@ -167,12 +167,12 @@
/**
* Indicates that there is an auxiliary (inline, not stack) argument
- * consisting of a <code>switch*</code> table.
+ * consisting of a {@code switch*} table.
*
* <p><b>Note:</b> This is generally used in conjunction with
* {@link #auxIntArg} (which holds the padding).</p>
*
- * @param cases non-null; the list of key-target pairs, plus the default
+ * @param cases {@code non-null;} the list of key-target pairs, plus the default
* target
*/
public void auxSwitchArg(SwitchList cases);
@@ -181,7 +181,7 @@
* Indicates that there is an auxiliary (inline, not stack) argument
* consisting of a list of initial values for a newly created array.
*
- * @param initValues non-null; the list of constant values to initialize
+ * @param initValues {@code non-null;} the list of constant values to initialize
* the array
*/
public void auxInitValues(ArrayList<Constant> initValues);
@@ -189,9 +189,9 @@
/**
* Indicates that the target of this operation is the given local.
*
- * @param idx >= 0; the local variable index
- * @param type non-null; the type of the local
- * @param local null-ok; the name and signature of the local, if known
+ * @param idx {@code >= 0;} the local variable index
+ * @param type {@code non-null;} the type of the local
+ * @param local {@code null-ok;} the name and signature of the local, if known
*/
public void localTarget(int idx, Type type, LocalItem local);
@@ -199,10 +199,10 @@
* "Runs" the indicated opcode in an appropriate way, using the arguments
* area as appropriate, and modifying the given frame in response.
*
- * @param frame non-null; frame to operate on
- * @param offset >= 0; byte offset in the method to the opcode being
+ * @param frame {@code non-null;} frame to operate on
+ * @param offset {@code >= 0;} byte offset in the method to the opcode being
* run
- * @param opcode >= 0; the opcode to run
+ * @param opcode {@code >= 0;} the opcode to run
*/
public void run(Frame frame, int offset, int opcode);
}
diff --git a/dx/src/com/android/dx/cf/code/Merger.java b/dx/src/com/android/dx/cf/code/Merger.java
index adeaab2..8da9a18 100644
--- a/dx/src/com/android/dx/cf/code/Merger.java
+++ b/dx/src/com/android/dx/cf/code/Merger.java
@@ -35,9 +35,9 @@
* 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 non-null; a locals array
- * @param locals2 non-null; another locals array
- * @return non-null; the result of merging the two locals arrays
+ * @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
*/
public static OneLocalsArray mergeLocals(OneLocalsArray locals1,
OneLocalsArray locals2) {
@@ -87,9 +87,9 @@
* Merges two stacks. If the merged result is the same as the first
* argument, then return the first argument (not a copy).
*
- * @param stack1 non-null; a stack
- * @param stack2 non-null; another stack
- * @return non-null; the result of merging the two stacks
+ * @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
*/
public static ExecutionStack mergeStack(ExecutionStack stack1,
ExecutionStack stack2) {
@@ -144,9 +144,9 @@
/**
* Merges two frame types.
*
- * @param ft1 non-null; a frame type
- * @param ft2 non-null; another frame type
- * @return non-null; the result of merging the two 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
*/
public static TypeBearer mergeType(TypeBearer ft1, TypeBearer ft2) {
if ((ft1 == null) || ft1.equals(ft2)) {
@@ -209,12 +209,12 @@
* the given subtype. This takes into account primitiveness,
* int-likeness, known-nullness, and array dimensions, but does
* not assume anything about class hierarchy other than that the
- * type <code>Object</code> is the supertype of all reference
+ * type {@code Object} is the supertype of all reference
* types and all arrays are assignable to
- * <code>Serializable</code> and <code>Cloneable</code>.
+ * {@code Serializable} and {@code Cloneable}.
*
- * @param supertypeBearer non-null; the supertype
- * @param subtypeBearer non-null; the subtype
+ * @param supertypeBearer {@code non-null;} the supertype
+ * @param subtypeBearer {@code non-null;} the subtype
*/
public static boolean isPossiblyAssignableFrom(TypeBearer supertypeBearer,
TypeBearer subtypeBearer) {
diff --git a/dx/src/com/android/dx/cf/code/OneLocalsArray.java b/dx/src/com/android/dx/cf/code/OneLocalsArray.java
index 3a590a1..cafd177 100644
--- a/dx/src/com/android/dx/cf/code/OneLocalsArray.java
+++ b/dx/src/com/android/dx/cf/code/OneLocalsArray.java
@@ -31,14 +31,14 @@
* com.android.dx.rop.type.TypeBearer}.</p>
*/
public class OneLocalsArray extends LocalsArray {
- /** non-null; actual array */
+ /** {@code non-null;} actual array */
private final TypeBearer[] locals;
/**
* Constructs an instance. The locals array initially consists of
- * all-uninitialized values (represented as <code>null</code>s).
+ * all-uninitialized values (represented as {@code null}s).
*
- * @param maxLocals >= 0; the maximum number of locals this instance
+ * @param maxLocals {@code >= 0;} the maximum number of locals this instance
* can refer to
*/
public OneLocalsArray(int maxLocals) {
@@ -237,7 +237,7 @@
* Throws a properly-formatted exception.
*
* @param idx the salient local index
- * @param msg non-null; useful message
+ * @param msg {@code non-null;} useful message
* @return never (keeps compiler happy)
*/
private static TypeBearer throwSimException(int idx, String msg) {
diff --git a/dx/src/com/android/dx/cf/code/ReturnAddress.java b/dx/src/com/android/dx/cf/code/ReturnAddress.java
index c69253c..47c6071 100644
--- a/dx/src/com/android/dx/cf/code/ReturnAddress.java
+++ b/dx/src/com/android/dx/cf/code/ReturnAddress.java
@@ -28,13 +28,13 @@
* what instances of this class hang onto.
*/
public final class ReturnAddress implements TypeBearer {
- /** >= 0; the start address of the subroutine being returned from */
+ /** {@code >= 0;} the start address of the subroutine being returned from */
private final int subroutineAddress;
/**
* Constructs an instance.
*
- * @param subroutineAddress >= 0; the start address of the
+ * @param subroutineAddress {@code >= 0;} the start address of the
* subroutine being returned from
*/
public ReturnAddress(int subroutineAddress) {
@@ -100,7 +100,7 @@
/**
* Gets the subroutine address.
*
- * @return >= 0; the subroutine address
+ * @return {@code >= 0;} the subroutine address
*/
public int getSubroutineAddress() {
return subroutineAddress;
diff --git a/dx/src/com/android/dx/cf/code/Ropper.java b/dx/src/com/android/dx/cf/code/Ropper.java
index f3eecab..6e8c328 100644
--- a/dx/src/com/android/dx/cf/code/Ropper.java
+++ b/dx/src/com/android/dx/cf/code/Ropper.java
@@ -66,10 +66,10 @@
/** number of special label offsets */
private static final int SPECIAL_LABEL_COUNT = 7;
- /** non-null; method being converted */
+ /** {@code non-null;} method being converted */
private final ConcreteMethod method;
- /** non-null; original block list */
+ /** {@code non-null;} original block list */
private final ByteBlockList blocks;
/** max locals of the method */
@@ -78,30 +78,30 @@
/** max label (exclusive) of any original bytecode block */
private final int maxLabel;
- /** non-null; simulation machine to use */
+ /** {@code non-null;} simulation machine to use */
private final RopperMachine machine;
- /** non-null; simulator to use */
+ /** {@code non-null;} simulator to use */
private final Simulator sim;
/**
- * non-null; sparse array mapping block labels to initial frame contents,
+ * {@code non-null;} sparse array mapping block labels to initial frame contents,
* if known
*/
private final Frame[] startFrames;
- /** non-null; output block list in-progress */
+ /** {@code non-null;} output block list in-progress */
private final ArrayList<BasicBlock> result;
/**
- * non-null; list of subroutine-nest labels
+ * {@code non-null;} list of subroutine-nest labels
* (See {@link Frame#getSubroutines} associated with each result block.
* Parallel to {@link Ropper#result}.
*/
private final ArrayList<IntList> resultSubroutines;
/**
- * non-null; for each block (by label) that is used as an exception
+ * {@code non-null;} for each block (by label) that is used as an exception
* handler, the type of exception it catches
*/
private final Type[] catchTypes;
@@ -112,10 +112,10 @@
*/
private boolean synchNeedsExceptionHandler;
- /** non-null; list of subroutines indexed by label of start address */
+ /** {@code non-null;} list of subroutines indexed by label of start address */
private final Subroutine subroutines[];
- /** true if <code>subroutines</code> is non-empty */
+ /** true if {@code subroutines} is non-empty */
private boolean hasSubroutines;
/**
@@ -155,7 +155,7 @@
}
/**
- * @return >= 0; the label of the subroutine's start block.
+ * @return {@code >= 0;} the label of the subroutine's start block.
*/
int getStartBlock() {
return startBlock;
@@ -194,13 +194,13 @@
IntList successors = new IntList(callerBlocks.size());
/*
- * For each subroutine caller, get it's target. If the target is us,
- * add the ret target (subroutine successor) to our list
+ * For each subroutine caller, get it's target. If the
+ * target is us, add the ret target (subroutine successor)
+ * to our list
*/
- for(int label = callerBlocks.nextSetBit(0); label >= 0
- ; label = callerBlocks.nextSetBit(label+1)) {
-
+ for (int label = callerBlocks.nextSetBit(0); label >= 0;
+ label = callerBlocks.nextSetBit(label+1)) {
BasicBlock subCaller = labelToBlock(label);
successors.add(subCaller.getSuccessors().get(0));
}
@@ -212,18 +212,15 @@
/**
* Merges the specified frame into this subroutine's successors,
- * setting <code>workSet</code> as appropriate. To be called with
+ * setting {@code workSet} as appropriate. To be called with
* the frame of a subroutine ret block.
*
- * @param frame non-null; frame from ret block to merge
- * @param workSet non-null; workset to update
+ * @param frame {@code non-null;} frame from ret block to merge
+ * @param workSet {@code non-null;} workset to update
*/
void mergeToSuccessors(Frame frame, int[] workSet) {
- int sz = callerBlocks.size();
-
- for(int label = callerBlocks.nextSetBit(0); label >= 0
- ; label = callerBlocks.nextSetBit(label+1)) {
-
+ for (int label = callerBlocks.nextSetBit(0); label >= 0;
+ label = callerBlocks.nextSetBit(label+1)) {
BasicBlock subCaller = labelToBlock(label);
int succLabel = subCaller.getSuccessors().get(0);
@@ -242,9 +239,9 @@
/**
* Converts a {@link ConcreteMethod} to a {@link RopMethod}.
*
- * @param method non-null; method to convert
- * @param advice non-null; translation advice to use
- * @return non-null; the converted instance
+ * @param method {@code non-null;} method to convert
+ * @param advice {@code non-null;} translation advice to use
+ * @return {@code non-null;} the converted instance
*/
public static RopMethod convert(ConcreteMethod method,
TranslationAdvice advice) {
@@ -263,8 +260,8 @@
* Constructs an instance. This class is not publicly instantiable; use
* {@link #convert}.
*
- * @param method non-null; method to convert
- * @param advice non-null; translation advice to use
+ * @param method {@code non-null;} method to convert
+ * @param advice {@code non-null;} translation advice to use
*/
private Ropper(ConcreteMethod method, TranslationAdvice advice) {
if (method == null) {
@@ -307,7 +304,7 @@
* Gets the first (lowest) register number to use as the temporary
* area when unwinding stack manipulation ops.
*
- * @return >= 0; the first register to use
+ * @return {@code >= 0;} the first register to use
*/
/*package*/ int getFirstTempStackReg() {
/*
@@ -326,8 +323,8 @@
* Gets the label for the exception handler setup block corresponding
* to the given label.
*
- * @param label >= 0; the original label
- * @return >= 0; the corresponding exception handler setup label
+ * @param label {@code >= 0;} the original label
+ * @return {@code >= 0;} the corresponding exception handler setup label
*/
private int getExceptionSetupLabel(int label) {
return maxLabel + label;
@@ -337,8 +334,8 @@
* Gets the label for the given special-purpose block. The given label
* should be one of the static constants defined by this class.
*
- * @param label < 0; the special label constant
- * @return >= 0; the actual label value to use
+ * @param label {@code < 0;} the special label constant
+ * @return {@code >= 0;} the actual label value to use
*/
private int getSpecialLabel(int label) {
/*
@@ -356,7 +353,7 @@
/**
* Gets the minimum label for unreserved use.
*
- * @return >= 0; the minimum label
+ * @return {@code >= 0;} the minimum label
*/
private int getMinimumUnreservedLabel() {
/*
@@ -370,7 +367,7 @@
/**
* Gets an arbitrary unreserved and available label.
*
- * @return >= 0; the label
+ * @return {@code >= 0;} the label
*/
private int getAvailableLabel() {
int candidate = getMinimumUnreservedLabel();
@@ -409,7 +406,7 @@
* Gets the total number of registers used for "normal" purposes (i.e.,
* for the straightforward translation from the original Java).
*
- * @return >= 0; the total number of registers used
+ * @return {@code >= 0;} the total number of registers used
*/
private int getNormalRegCount() {
return maxLocals + method.getMaxStack();
@@ -419,7 +416,7 @@
* Gets the register spec to use to hold the object to synchronize on,
* for a synchronized method.
*
- * @return non-null; the register spec
+ * @return {@code non-null;} the register spec
*/
private RegisterSpec getSynchReg() {
/*
@@ -433,11 +430,11 @@
/**
* Searches {@link #result} for a block with the given label. Return its
- * index if found, or return <code>-1</code> if there is no such block.
+ * index if found, or return {@code -1} if there is no such block.
*
* @param label the label to look for
- * @return >= -1; the index for the block with the given label or
- * <code>-1</code> if there is no such block
+ * @return {@code >= -1;} the index for the block with the given label or
+ * {@code -1} if there is no such block
*/
private int labelToResultIndex(int label) {
int sz = result.size();
@@ -456,7 +453,7 @@
* found, or throw an exception if there is no such block.
*
* @param label the label to look for
- * @return non-null; the block with the given label
+ * @return {@code non-null;} the block with the given label
*/
private BasicBlock labelToBlock(int label) {
int idx = labelToResultIndex(label);
@@ -472,8 +469,8 @@
/**
* Adds a block to the output result.
*
- * @param block non-null; the block to add
- * @param subroutines non-null; subroutine label list as described in
+ * @param block {@code non-null;} the block to add
+ * @param subroutines {@code non-null;} subroutine label list as described in
* {@link Frame#getSubroutines}
*/
private void addBlock(BasicBlock block, IntList subroutines) {
@@ -491,11 +488,11 @@
* replacement, then any extra blocks that got added with the
* original get removed as a result of calling this method.
*
- * @param block non-null; the block to add or replace
- * @param subroutines non-null; subroutine label list as described in
+ * @param block {@code non-null;} the block to add or replace
+ * @param subroutines {@code non-null;} subroutine label list as described in
* {@link Frame#getSubroutines}
- * @return <code>true</code> if the block was replaced or
- * <code>false</code> if it was added for the first time
+ * @return {@code true} if the block was replaced or
+ * {@code false} if it was added for the first time
*/
private boolean addOrReplaceBlock(BasicBlock block, IntList subroutines) {
if (block == null) {
@@ -529,11 +526,11 @@
* Adds or replaces a block in the output result. Do not delete
* any successors.
*
- * @param block non-null; the block to add or replace
- * @param subroutines non-null; subroutine label list as described in
+ * @param block {@code non-null;} the block to add or replace
+ * @param subroutines {@code non-null;} subroutine label list as described in
* {@link Frame#getSubroutines}
- * @return <code>true</code> if the block was replaced or
- * <code>false</code> if it was added for the first time
+ * @return {@code true} if the block was replaced or
+ * {@code false} if it was added for the first time
*/
private boolean addOrReplaceBlockNoDelete(BasicBlock block,
IntList subroutines) {
@@ -564,7 +561,7 @@
* successors of it whose labels indicate that they are not in the
* normally-translated range.
*
- * @param idx non-null; block to remove (etc.)
+ * @param idx {@code non-null;} block to remove (etc.)
*/
private void removeBlockAndSpecialSuccessors(int idx) {
int minLabel = getMinimumUnreservedLabel();
@@ -591,7 +588,7 @@
/**
* Extracts the resulting {@link RopMethod} from the instance.
*
- * @return non-null; the method object
+ * @return {@code non-null;} the method object
*/
private RopMethod getRopMethod() {
@@ -663,9 +660,9 @@
/**
* Processes the given block.
*
- * @param block non-null; block to process
- * @param frame non-null; start frame for the block
- * @param workSet non-null; bits representing work to do, which this
+ * @param block {@code non-null;} block to process
+ * @param frame {@code non-null;} start frame for the block
+ * @param workSet {@code non-null;} bits representing work to do, which this
* method may add to
*/
private void processBlock(ByteBlock block, Frame frame, int[] workSet) {
@@ -950,14 +947,14 @@
* Helper for {@link #processBlock}, which merges frames and
* adds to the work set, as necessary.
*
- * @param label >= 0; label to work on
- * @param pred predecessor label. Must be >= 0 when
- * <code>label</code> is a subroutine start block and calledSubroutine
+ * @param label {@code >= 0;} label to work on
+ * @param pred predecessor label; must be {@code >= 0} when
+ * {@code label} is a subroutine start block and calledSubroutine
* is non-null. Otherwise, may be -1.
- * @param calledSubroutine null-ok; a Subroutine instance if
- * <code>label</code> is the first block in a subroutine.
- * @param frame non-null; new frame for the labelled block
- * @param workSet non-null; bits representing work to do, which this
+ * @param calledSubroutine {@code null-ok;} a Subroutine instance if
+ * {@code label} is the first block in a subroutine.
+ * @param frame {@code non-null;} new frame for the labelled block
+ * @param workSet {@code non-null;} bits representing work to do, which this
* method may add to
*/
private void mergeAndWorkAsNecessary(int label, int pred,
@@ -1078,7 +1075,7 @@
/**
* Constructs and adds the return block, if necessary. The return
- * block merely contains an appropriate <code>return</code>
+ * block merely contains an appropriate {@code return}
* instruction.
*/
private void addReturnBlock() {
@@ -1217,7 +1214,7 @@
/**
* Checks to see if the basic block is a subroutine caller block.
*
- * @param bb non-null; the basic block in question
+ * @param bb {@code non-null;} the basic block in question
* @return true if this block calls a subroutine
*/
private boolean isSubroutineCaller(BasicBlock bb) {
@@ -1340,7 +1337,7 @@
/**
* Inlines a subroutine. Start by calling
- * <code>inlineSubroutineCalledFrom</code>.
+ * {@code inlineSubroutineCalledFrom}.
*/
private class SubroutineInliner {
/**
@@ -1399,9 +1396,8 @@
*/
int newSubStartLabel = mapOrAllocateLabel(subroutineStart);
- for(int label = workList.nextSetBit(0); label >= 0
- ; label = workList.nextSetBit(0)) {
-
+ for (int label = workList.nextSetBit(0); label >= 0;
+ label = workList.nextSetBit(0)) {
workList.clear(label);
int newLabel = origLabelToCopiedLabel.get(label);
@@ -1421,7 +1417,8 @@
addOrReplaceBlockNoDelete(
new BasicBlock(b.getLabel(), b.getInsns(),
IntList.makeImmutable (newSubStartLabel),
- newSubStartLabel), labelToSubroutines.get(b.getLabel()));
+ newSubStartLabel),
+ labelToSubroutines.get(b.getLabel()));
}
/**
@@ -1502,8 +1499,8 @@
* Checks to see if a specified label is involved in a specified
* subroutine.
*
- * @param label >=0 a basic block label
- * @param subroutineStart >=0 a subroutine as identified by the
+ * @param label {@code >= 0;} a basic block label
+ * @param subroutineStart {@code >= 0;} a subroutine as identified by the
* label of its start block.
* @return true if the block is dominated by the subroutine call.
*/
@@ -1554,10 +1551,10 @@
}
/**
- * Finds a <code>Subroutine<code> that is returned from by a ret in
+ * Finds a {@code Subroutine} that is returned from by a ret in
* a given block.
* @param label A block that originally contained a ret instruction
- * @return null-ok; Subroutine or null if none was found.
+ * @return {@code null-ok;} Subroutine or null if none was found.
*/
private Subroutine subroutineFromRetBlock(int label) {
for (int i = subroutines.length - 1 ; i >= 0 ; i--) {
diff --git a/dx/src/com/android/dx/cf/code/RopperMachine.java b/dx/src/com/android/dx/cf/code/RopperMachine.java
index 6d05b38..dd7fcd4 100644
--- a/dx/src/com/android/dx/cf/code/RopperMachine.java
+++ b/dx/src/com/android/dx/cf/code/RopperMachine.java
@@ -47,13 +47,13 @@
* Machine implementation for use by {@link Ropper}.
*/
/*package*/ final class RopperMachine extends ValueAwareMachine {
- /** non-null; array reflection class */
+ /** {@code non-null;} array reflection class */
private static final CstType ARRAY_REFLECT_TYPE =
new CstType(Type.internClassName("java/lang/reflect/Array"));
/**
- * non-null; method constant for use in converting
- * <code>multianewarray</code> instructions
+ * {@code non-null;} method constant for use in converting
+ * {@code multianewarray} instructions
*/
private static final CstMethodRef MULTIANEWARRAY_METHOD =
new CstMethodRef(ARRAY_REFLECT_TYPE,
@@ -61,34 +61,34 @@
new CstUtf8("(Ljava/lang/Class;[I)" +
"Ljava/lang/Object;")));
- /** non-null; {@link Ropper} controlling this instance */
+ /** {@code non-null;} {@link Ropper} controlling this instance */
private final Ropper ropper;
- /** non-null; method being converted */
+ /** {@code non-null;} method being converted */
private final ConcreteMethod method;
- /** non-null; translation advice */
+ /** {@code non-null;} translation advice */
private final TranslationAdvice advice;
/** max locals of the method */
private final int maxLocals;
- /** non-null; instructions for the rop basic block in-progress */
+ /** {@code non-null;} instructions for the rop basic block in-progress */
private final ArrayList<Insn> insns;
- /** non-null; catches for the block currently being processed */
+ /** {@code non-null;} catches for the block currently being processed */
private TypeList catches;
/** whether the catches have been used in an instruction */
private boolean catchesUsed;
- /** whether the block contains a <code>return</code> */
+ /** whether the block contains a {@code return} */
private boolean returns;
/** primary successor index */
private int primarySuccessorIndex;
- /** >= 0; number of extra basic blocks required */
+ /** {@code >= 0;} number of extra basic blocks required */
private int extraBlockCount;
/** true if last processed block ends with a jsr or jsr_W*/
@@ -105,13 +105,13 @@
private ReturnAddress returnAddress;
/**
- * null-ok; the appropriate <code>return</code> op or <code>null</code>
+ * {@code null-ok;} the appropriate {@code return} op or {@code null}
* if it is not yet known
*/
private Rop returnOp;
/**
- * null-ok; the source position for the return block or <code>null</code>
+ * {@code null-ok;} the source position for the return block or {@code null}
* if it is not yet known
*/
private SourcePosition returnPosition;
@@ -119,9 +119,9 @@
/**
* Constructs an instance.
*
- * @param ropper non-null; ropper controlling this instance
- * @param method non-null; method being converted
- * @param advice non-null; translation advice to use
+ * @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
*/
public RopperMachine(Ropper ropper, ConcreteMethod method,
TranslationAdvice advice) {
@@ -154,7 +154,7 @@
* Gets the instructions array. It is shared and gets modified by
* subsequent calls to this instance.
*
- * @return non-null; the instructions array
+ * @return {@code non-null;} the instructions array
*/
public ArrayList<Insn> getInsns() {
return insns;
@@ -163,7 +163,7 @@
/**
* Gets the return opcode encountered, if any.
*
- * @return null-ok; the return opcode
+ * @return {@code null-ok;} the return opcode
*/
public Rop getReturnOp() {
return returnOp;
@@ -172,7 +172,7 @@
/**
* Gets the return position, if known.
*
- * @return null-ok; the return position
+ * @return {@code null-ok;} the return position
*/
public SourcePosition getReturnPosition() {
return returnPosition;
@@ -182,7 +182,7 @@
* Gets ready to start working on a new block. This will clear the
* {@link #insns} list, set {@link #catches}, reset whether it has
* been used, reset whether the block contains a
- * <code>return</code>, and reset {@link #primarySuccessorIndex}.
+ * {@code return}, and reset {@link #primarySuccessorIndex}.
*/
public void startBlock(TypeList catches) {
this.catches = catches;
@@ -201,7 +201,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</code> has been used
+ * @return whether {@code catches} has been used
*/
public boolean wereCatchesUsed() {
return catchesUsed;
@@ -209,7 +209,7 @@
/**
* Gets whether the block just processed ended with a
- * <code>return</code>.
+ * {@code return}.
*
* @return whether the block returns
*/
@@ -220,12 +220,12 @@
/**
* Gets the primary successor index. This is the index into the
* successors list where the primary may be found or
- * <code>-1</code> if there are successors but no primary
+ * {@code -1} if there are successors but no primary
* successor. This may return something other than
- * <code>-1</code> in the case of an instruction with no
+ * {@code -1} in the case of an instruction with no
* successors at all (primary or otherwise).
*
- * @return >= -1; the primary successor index
+ * @return {@code >= -1;} the primary successor index
*/
public int getPrimarySuccessorIndex() {
return primarySuccessorIndex;
@@ -236,7 +236,7 @@
* block currently being translated. Each extra block should consist
* of one instruction from the end of the original block.
*
- * @return >= 0; the number of extra blocks needed
+ * @return {@code >= 0;} the number of extra blocks needed
*/
public int getExtraBlockCount() {
return extraBlockCount;
@@ -259,16 +259,17 @@
}
/**
- * @return true if a RET has ben encountered since the last call to
- * startBlock()
+ * @return {@code true} if a {@code ret} has ben encountered since
+ * the last call to {@code startBlock()}
*/
public boolean hasRet() {
return returnAddress != null;
}
/**
- * @return null-ok; return address of a ret instruction if encountered
- * since last call to startBlock(). null if no ret instruction encountered.
+ * @return {@code null-ok;} return address of a {@code ret}
+ * instruction if encountered since last call to startBlock().
+ * {@code null} if no ret instruction encountered.
*/
public ReturnAddress getReturnAddress() {
return returnAddress;
@@ -444,7 +445,7 @@
catches, MULTIANEWARRAY_METHOD);
insns.add(insn);
- // Add a move-result
+ // Add a move-result.
rop = Rops.opMoveResult(MULTIANEWARRAY_METHOD.getPrototype()
.getReturnType());
insn = new PlainInsn(rop, pos, objectReg, RegisterSpecList.EMPTY);
@@ -457,7 +458,6 @@
opcode = ByteOps.CHECKCAST;
sources = RegisterSpecList.make(objectReg);
-
} else if (opcode == ByteOps.JSR) {
// JSR has no Rop instruction
hasJsr = true;
@@ -474,12 +474,14 @@
}
ropOpcode = jopToRopOpcode(opcode, cst);
-
rop = Rops.ropFor(ropOpcode, destType, sources, cst);
Insn moveResult = null;
if (dest != null && rop.isCallLike()) {
- // We're going to want to have a move-result in the next basic block
+ /*
+ * We're going to want to have a move-result in the next
+ * basic block.
+ */
extraBlockCount++;
moveResult = new PlainInsn(
@@ -488,8 +490,10 @@
dest = null;
} else if (dest != null && rop.canThrow()) {
- // We're going to want to have a move-result-pseudo
- // in the next basic block
+ /*
+ * We're going to want to have a move-result-pseudo in the
+ * next basic block.
+ */
extraBlockCount++;
moveResult = new PlainInsn(
@@ -599,11 +603,12 @@
}
/*
- * If initValues is non-null, it means that the parser has seen a group
- * of compatible constant initialization bytecodes that are applied to
- * the current newarray. The 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 is non-null, it means that the parser has
+ * seen a group of compatible constant initialization
+ * bytecodes that are applied to the current newarray. The
+ * 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++;
@@ -619,9 +624,9 @@
* instruction.
*
* @param opcode the opcode being translated
- * @param stackPointer >= 0; the stack pointer after the instruction's
- * arguments have been popped
- * @return non-null; the sources
+ * @param stackPointer {@code >= 0;} the stack pointer after the
+ * instruction's arguments have been popped
+ * @return {@code non-null;} the sources
*/
private RegisterSpecList getSources(int opcode, int stackPointer) {
int count = argCount();
@@ -692,8 +697,8 @@
/**
* Sets or updates the information about the return block.
*
- * @param op non-null; the opcode to use
- * @param pos non-null; the position to use
+ * @param op {@code non-null;} the opcode to use
+ * @param pos {@code non-null;} the position to use
*/
private void updateReturnOp(Rop op, SourcePosition pos) {
if (op == null) {
@@ -723,9 +728,9 @@
/**
* Gets the register opcode for the given Java opcode.
*
- * @param jop >= 0; the Java opcode
- * @param cst null-ok; the constant argument, if any
- * @return >= 0; the corresponding register 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
*/
private int jopToRopOpcode(int jop, Constant cst) {
switch (jop) {
diff --git a/dx/src/com/android/dx/cf/code/Simulator.java b/dx/src/com/android/dx/cf/code/Simulator.java
index 3c90ee5..408e126 100644
--- a/dx/src/com/android/dx/cf/code/Simulator.java
+++ b/dx/src/com/android/dx/cf/code/Simulator.java
@@ -35,34 +35,37 @@
/**
* Class which knows how to simulate the effects of executing bytecode.
- *
+ *
* <p><b>Note:</b> This class is not thread-safe. If multiple threads
* need to use a single instance, they must synchronize access explicitly
* between themselves.</p>
*/
public class Simulator {
- /** non-null; canned error message for local variable table mismatches */
- private static final String LOCAL_MISMATCH_ERROR =
+ /**
+ * {@code non-null;} canned error message for local variable
+ * table mismatches
+ */
+ private static final String LOCAL_MISMATCH_ERROR =
"This is symptomatic of .class transformation tools that ignore " +
"local variable information.";
- /** non-null; machine to use when simulating */
+ /** {@code non-null;} machine to use when simulating */
private final Machine machine;
- /** non-null; array of bytecode */
+ /** {@code non-null;} array of bytecode */
private final BytecodeArray code;
- /** non-null; local variable information */
+ /** {@code non-null;} local variable information */
private final LocalVariableList localVariables;
- /** non-null; visitor instance to use */
+ /** {@code non-null;} visitor instance to use */
private final SimVisitor visitor;
/**
* Constructs an instance.
*
- * @param machine non-null; machine to use when simulating
- * @param method non-null; method data to use
+ * @param machine {@code non-null;} machine to use when simulating
+ * @param method {@code non-null;} method data to use
*/
public Simulator(Machine machine, ConcreteMethod method) {
if (machine == null) {
@@ -83,8 +86,8 @@
* Simulates the effect of executing the given basic block. This modifies
* the passed-in frame to represent the end result.
*
- * @param bb non-null; the basic block
- * @param frame non-null; frame to operate on
+ * @param bb {@code non-null;} the basic block
+ * @param frame {@code non-null;} frame to operate on
*/
public void simulate(ByteBlock bb, Frame frame) {
int end = bb.getEnd();
@@ -107,8 +110,8 @@
* Simulates the effect of the instruction at the given offset, by
* making appropriate calls on the given frame.
*
- * @param offset >= 0; offset of the instruction to simulate
- * @param frame non-null; frame to operate on
+ * @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
*/
public int simulate(int offset, Frame frame) {
@@ -130,13 +133,13 @@
*/
private class SimVisitor implements BytecodeArray.Visitor {
/**
- * non-null; machine instance to use (just to avoid excessive
- * cross-object field access)
+ * {@code non-null;} machine instance to use (just to avoid excessive
+ * cross-object field access)
*/
private final Machine machine;
/**
- * 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;
@@ -155,7 +158,7 @@
/**
* Sets the frame to act on.
*
- * @param frame non-null; the frame
+ * @param frame {@code non-null;} the frame
*/
public void setFrame(Frame frame) {
if (frame == null) {
@@ -255,25 +258,21 @@
/*
* Change the type (which is to be pushed) to
* reflect the actual component type of the array
- * being popped.
+ * being popped, unless it turns out to be a
+ * known-null, in which case we just use the type
+ * implied by the original instruction.
*/
- Type requireType = type.getArrayType();
- type = frame.getStack().peekType(1);
- if (type == Type.KNOWN_NULL) {
- /*
- * The type is a known-null: Just treat the
- * popped type as whatever is expected. In
- * reality, unless this frame is revisited
- * (due to a branch merge), execution will
- * result in the throwing of a
- * NullPointerException, but claiming the
- * expected type at here should be good enough
- * for the purposes at this level.
- */
- type = requireType;
+ Type foundArrayType = frame.getStack().peekType(1);
+ Type requireArrayType;
+
+ if (foundArrayType != Type.KNOWN_NULL) {
+ requireArrayType = foundArrayType;
+ type = foundArrayType.getComponentType();
+ } else {
+ requireArrayType = type.getArrayType();
}
- type = type.getComponentType();
- machine.popArgs(frame, requireType, Type.INT);
+
+ machine.popArgs(frame, requireArrayType, Type.INT);
break;
}
case ByteOps.IADD:
@@ -292,7 +291,7 @@
case ByteOps.IUSHR: {
machine.popArgs(frame, type, Type.INT);
break;
- }
+ }
case ByteOps.LCMP: {
machine.popArgs(frame, Type.LONG, Type.LONG);
break;
@@ -308,8 +307,28 @@
break;
}
case ByteOps.IASTORE: {
- Type arrayType = type.getArrayType();
- machine.popArgs(frame, arrayType, Type.INT, type);
+ /*
+ * Change the type (which is the type of the
+ * element) to reflect the actual component type
+ * of the array being popped, unless it turns out
+ * to be a known-null, in which case we just use
+ * the type implied by the original instruction.
+ * The category 1 vs. 2 thing here is that, if the
+ * element type is category 2, we have to skip over
+ * one extra stack slot to find the array.
+ */
+ Type foundArrayType =
+ frame.getStack().peekType(type.isCategory1() ? 2 : 3);
+ Type requireArrayType;
+
+ if (foundArrayType != Type.KNOWN_NULL) {
+ requireArrayType = foundArrayType;
+ type = foundArrayType.getComponentType();
+ } else {
+ requireArrayType = type.getArrayType();
+ }
+
+ machine.popArgs(frame, requireArrayType, Type.INT, type);
break;
}
case ByteOps.POP2:
@@ -456,7 +475,7 @@
* Checks whether the prototype is compatible with returning the
* given type, and throws if not.
*
- * @param encountered non-null; the encountered return type
+ * @param encountered {@code non-null;} the encountered return type
*/
private void checkReturnType(Type encountered) {
Type returnType = machine.getPrototype().getReturnType();
diff --git a/dx/src/com/android/dx/cf/code/SwitchList.java b/dx/src/com/android/dx/cf/code/SwitchList.java
index dc04137..fdd1596 100644
--- a/dx/src/com/android/dx/cf/code/SwitchList.java
+++ b/dx/src/com/android/dx/cf/code/SwitchList.java
@@ -21,15 +21,15 @@
/**
* List of (value, target) mappings representing the choices of a
- * <code>tableswitch</code> or <code>lookupswitch</code> instruction. It
+ * {@code tableswitch} or {@code lookupswitch} instruction. It
* also holds the default target for the switch.
*/
public final class SwitchList extends MutabilityControl {
- /** non-null; list of test values */
+ /** {@code non-null;} list of test values */
private final IntList values;
/**
- * non-null; list of targets corresponding to the test values; there
+ * {@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
*/
@@ -41,7 +41,7 @@
/**
* Constructs an instance.
*
- * @param size >= 0; the number of elements to be in the table
+ * @param size {@code >= 0;} the number of elements to be in the table
*/
public SwitchList(int size) {
super(true);
@@ -61,7 +61,7 @@
/**
* Gets the size of the list.
*
- * @return >= 0; the list size
+ * @return {@code >= 0;} the list size
*/
public int size() {
return size;
@@ -70,7 +70,7 @@
/**
* Gets the indicated test value.
*
- * @param n >= 0;, < size(); which index
+ * @param n {@code >= 0;}, < size(); which index
* @return the test value
*/
public int getValue(int n) {
@@ -78,11 +78,11 @@
}
/**
- * Gets the indicated target. Asking for the target at <code>size()</code>
+ * Gets the indicated target. Asking for the target at {@code size()}
* returns the default target.
*
- * @param n >= 0, <= size(); which index
- * @return >= 0; the target
+ * @param n {@code >= 0, <= size();} which index
+ * @return {@code >= 0;} the target
*/
public int getTarget(int n) {
return targets.get(n);
@@ -90,9 +90,9 @@
/**
* Gets the default target. This is just a shorthand for
- * <code>getTarget(size())</code>.
+ * {@code getTarget(size())}.
*
- * @return >= 0; the default target
+ * @return {@code >= 0;} the default target
*/
public int getDefaultTarget() {
return targets.get(size);
@@ -102,7 +102,7 @@
* Gets the list of all targets. This includes one extra element at the
* end of the list, which holds the default target.
*
- * @return non-null; the target list
+ * @return {@code non-null;} the target list
*/
public IntList getTargets() {
return targets;
@@ -111,7 +111,7 @@
/**
* Gets the list of all case values.
*
- * @return non-null; the case value list
+ * @return {@code non-null;} the case value list
*/
public IntList getValues() {
return values;
@@ -121,7 +121,7 @@
* Sets the default target. It is only valid to call this method
* when all the non-default elements have been set.
*
- * @param target >= 0; the absolute (not relative) default target
+ * @param target {@code >= 0;} the absolute (not relative) default target
* address
*/
public void setDefaultTarget(int target) {
@@ -142,7 +142,7 @@
* Adds the given item.
*
* @param value the test value
- * @param target >= 0; the absolute (not relative) target address
+ * @param target {@code >= 0;} the absolute (not relative) target address
*/
public void add(int value, int target) {
throwIfImmutable();
diff --git a/dx/src/com/android/dx/cf/code/ValueAwareMachine.java b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
index 4062c3b..43aab8a 100644
--- a/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
+++ b/dx/src/com/android/dx/cf/code/ValueAwareMachine.java
@@ -30,7 +30,8 @@
/**
* Constructs an instance.
*
- * @param prototype non-null; the prototype for the associated method
+ * @param prototype {@code non-null;} the prototype for the associated
+ * method
*/
public ValueAwareMachine(Prototype prototype) {
super(prototype);
diff --git a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
index 953981c..7cd9c9b 100644
--- a/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
+++ b/dx/src/com/android/dx/cf/cst/ConstantPoolParser.java
@@ -41,29 +41,29 @@
* Parser for a constant pool embedded in a class file.
*/
public final class ConstantPoolParser {
- /** non-null; the bytes of the constant pool */
+ /** {@code non-null;} the bytes of the constant pool */
private final ByteArray bytes;
- /** non-null; actual parsed constant pool contents */
+ /** {@code non-null;} actual parsed constant pool contents */
private final StdConstantPool pool;
- /** non-null; byte offsets to each cst */
+ /** {@code non-null;} byte offsets to each cst */
private final int[] offsets;
/**
* -1 || >= 10; the end offset of this constant pool in the
- * <code>byte[]</code> which it came from or <code>-1</code> if not
+ * {@code byte[]} which it came from or {@code -1} if not
* yet parsed
*/
private int endOffset;
- /** null-ok; parse observer, if any */
+ /** {@code null-ok;} parse observer, if any */
private ParseObserver observer;
/**
* Constructs an instance.
*
- * @param bytes non-null; the bytes of the file
+ * @param bytes {@code non-null;} the bytes of the file
*/
public ConstantPoolParser(ByteArray bytes) {
int size = bytes.getUnsignedShort(8); // constant_pool_count
@@ -77,17 +77,17 @@
/**
* Sets the parse observer for this instance.
*
- * @param observer null-ok; the observer
+ * @param observer {@code null-ok;} the observer
*/
public void setObserver(ParseObserver observer) {
this.observer = observer;
}
/**
- * Gets the end offset of this constant pool in the <code>byte[]</code>
+ * Gets the end offset of this constant pool in the {@code byte[]}
* which it came from.
*
- * @return >= 10; the end offset
+ * @return {@code >= 10;} the end offset
*/
public int getEndOffset() {
parseIfNecessary();
@@ -97,7 +97,7 @@
/**
* Gets the actual constant pool.
*
- * @return non-null; the constant pool
+ * @return {@code non-null;} the constant pool
*/
public StdConstantPool getPool() {
parseIfNecessary();
@@ -215,7 +215,7 @@
* depends on.
*
* @param idx which constant
- * @return non-null; the parsed constant
+ * @return {@code non-null;} the parsed constant
*/
private Constant parse0(int idx) {
Constant cst = pool.getOrNull(idx);
@@ -316,7 +316,7 @@
* Parses a utf8 constant.
*
* @param at offset to the start of the constant (where the tag byte is)
- * @return non-null; the parsed value
+ * @return {@code non-null;} the parsed value
*/
private CstUtf8 parseUtf8(int at) {
int length = bytes.getUnsignedShort(at + 1);
diff --git a/dx/src/com/android/dx/cf/cst/ConstantTags.java b/dx/src/com/android/dx/cf/cst/ConstantTags.java
index 64bc8d8..9febbdf 100644
--- a/dx/src/com/android/dx/cf/cst/ConstantTags.java
+++ b/dx/src/com/android/dx/cf/cst/ConstantTags.java
@@ -20,36 +20,36 @@
* Tags for constant pool constants.
*/
public interface ConstantTags {
- /** tag for a <code>CONSTANT_Utf8_info</code> */
+ /** tag for a {@code CONSTANT_Utf8_info} */
int CONSTANT_Utf8 = 1;
- /** tag for a <code>CONSTANT_Integer_info</code> */
+ /** tag for a {@code CONSTANT_Integer_info} */
int CONSTANT_Integer = 3;
- /** tag for a <code>CONSTANT_Float_info</code> */
+ /** tag for a {@code CONSTANT_Float_info} */
int CONSTANT_Float = 4;
- /** tag for a <code>CONSTANT_Long_info</code> */
+ /** tag for a {@code CONSTANT_Long_info} */
int CONSTANT_Long = 5;
- /** tag for a <code>CONSTANT_Double_info</code> */
+ /** tag for a {@code CONSTANT_Double_info} */
int CONSTANT_Double = 6;
- /** tag for a <code>CONSTANT_Class_info</code> */
+ /** tag for a {@code CONSTANT_Class_info} */
int CONSTANT_Class = 7;
- /** tag for a <code>CONSTANT_String_info</code> */
+ /** tag for a {@code CONSTANT_String_info} */
int CONSTANT_String = 8;
- /** tag for a <code>CONSTANT_Fieldref_info</code> */
+ /** tag for a {@code CONSTANT_Fieldref_info} */
int CONSTANT_Fieldref = 9;
- /** tag for a <code>CONSTANT_Methodref_info</code> */
+ /** tag for a {@code CONSTANT_Methodref_info} */
int CONSTANT_Methodref = 10;
- /** tag for a <code>CONSTANT_InterfaceMethodref_info</code> */
+ /** tag for a {@code CONSTANT_InterfaceMethodref_info} */
int CONSTANT_InterfaceMethodref = 11;
- /** tag for a <code>CONSTANT_NameAndType_info</code> */
+ /** tag for a {@code CONSTANT_NameAndType_info} */
int CONSTANT_NameAndType = 12;
}
diff --git a/dx/src/com/android/dx/cf/direct/AnnotationParser.java b/dx/src/com/android/dx/cf/direct/AnnotationParser.java
index 5d80086..88e4cd2 100644
--- a/dx/src/com/android/dx/cf/direct/AnnotationParser.java
+++ b/dx/src/com/android/dx/cf/direct/AnnotationParser.java
@@ -51,23 +51,23 @@
* Parser for annotations.
*/
public final class AnnotationParser {
- /** non-null; class file being parsed */
+ /** {@code non-null;} class file being parsed */
private final DirectClassFile cf;
- /** non-null; constant pool to use */
+ /** {@code non-null;} constant pool to use */
private final ConstantPool pool;
- /** non-null; bytes of the attribute data */
+ /** {@code non-null;} bytes of the attribute data */
private final ByteArray bytes;
- /** null-ok; parse observer, if any */
+ /** {@code null-ok;} parse observer, if any */
private final ParseObserver observer;
- /** non-null; input stream to parse from */
+ /** {@code non-null;} input stream to parse from */
private final ByteArray.MyDataInputStream input;
/**
- * non-null; cursor for use when informing the observer of what
+ * {@code non-null;} cursor for use when informing the observer of what
* was parsed
*/
private int parseCursor;
@@ -75,10 +75,10 @@
/**
* Constructs an instance.
*
- * @param cf non-null; class file to parse from
- * @param offset >= 0; offset into the class file data to parse at
- * @param length >= 0; number of bytes left in the attribute data
- * @param observer null-ok; parse observer to notify, if any
+ * @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
+ * @param observer {@code null-ok;} parse observer to notify, if any
*/
public AnnotationParser(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -95,9 +95,9 @@
}
/**
- * Parses an annotation value (<code>element_value</code>) attribute.
+ * Parses an annotation value ({@code element_value}) attribute.
*
- * @return non-null; the parsed constant value
+ * @return {@code non-null;} the parsed constant value
*/
public Constant parseValueAttribute() {
Constant result;
@@ -119,8 +119,8 @@
/**
* Parses a parameter annotation attribute.
*
- * @param visibility non-null; visibility of the parsed annotations
- * @return non-null; the parsed list of lists of annotations
+ * @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) {
@@ -143,8 +143,8 @@
/**
* Parses an annotation attribute, per se.
*
- * @param visibility non-null; visibility of the parsed annotations
- * @return non-null; the list of annotations read from the attribute
+ * @param visibility {@code non-null;} visibility of the parsed annotations
+ * @return {@code non-null;} the list of annotations read from the attribute
* data
*/
public Annotations parseAnnotationAttribute(
@@ -168,8 +168,8 @@
/**
* Parses a list of annotation lists.
*
- * @param visibility non-null; visibility of the parsed annotations
- * @return non-null; the list of annotation lists read from the attribute
+ * @param visibility {@code non-null;} visibility of the parsed annotations
+ * @return {@code non-null;} the list of annotation lists read from the attribute
* data
*/
private AnnotationsList parseAnnotationsList(
@@ -203,8 +203,8 @@
/**
* Parses an annotation list.
*
- * @param visibility non-null; visibility of the parsed annotations
- * @return non-null; the list of annotations read from the attribute
+ * @param visibility {@code non-null;} visibility of the parsed annotations
+ * @return {@code non-null;} the list of annotations read from the attribute
* data
*/
private Annotations parseAnnotations(AnnotationVisibility visibility)
@@ -238,8 +238,8 @@
/**
* Parses a single annotation.
*
- * @param visibility non-null; visibility of the parsed annotation
- * @return non-null; the parsed annotation
+ * @param visibility {@code non-null;} visibility of the parsed annotation
+ * @return {@code non-null;} the parsed annotation
*/
private Annotation parseAnnotation(AnnotationVisibility visibility)
throws IOException {
@@ -278,7 +278,7 @@
/**
* Parses a {@link NameValuePair}.
*
- * @return non-null; the parsed element
+ * @return {@code non-null;} the parsed element
*/
private NameValuePair parseElement() throws IOException {
requireLength(5);
@@ -304,7 +304,7 @@
/**
* Parses an annotation value.
*
- * @return non-null; the parsed value
+ * @return {@code non-null;} the parsed value
*/
private Constant parseValue() throws IOException {
int tag = input.readUnsignedByte();
@@ -421,7 +421,7 @@
* Helper for {@link #parseValue}, which parses a constant reference
* and returns the referred-to constant value.
*
- * @return non-null; the parsed value
+ * @return {@code non-null;} the parsed value
*/
private Constant parseConstant() throws IOException {
int constValueIndex = input.readUnsignedShort();
@@ -454,8 +454,8 @@
* only be used (for efficiency sake) if the parse is known to be
* observed.
*
- * @param length >= 0; number of bytes parsed
- * @param message non-null; associated message
+ * @param length {@code >= 0;} number of bytes parsed
+ * @param message {@code non-null;} associated message
*/
private void parsed(int length, String message) {
observer.parsed(bytes, parseCursor, length, message);
@@ -464,7 +464,7 @@
/**
* Convenience wrapper that simply calls through to
- * <code>observer.changeIndent()</code>.
+ * {@code observer.changeIndent()}.
*
* @param indent the amount to change the indent by
*/
diff --git a/dx/src/com/android/dx/cf/direct/AttributeFactory.java b/dx/src/com/android/dx/cf/direct/AttributeFactory.java
index 420d741..d00a859 100644
--- a/dx/src/com/android/dx/cf/direct/AttributeFactory.java
+++ b/dx/src/com/android/dx/cf/direct/AttributeFactory.java
@@ -58,13 +58,13 @@
* the name, and then does all the setup to call on to {@link #parse0},
* which does the actual construction.
*
- * @param cf non-null; class file to parse from
- * @param context context to parse in; one of the <code>CTX_*</code>
+ * @param cf {@code non-null;} class file to parse from
+ * @param context context to parse in; one of the {@code CTX_*}
* constants
- * @param offset offset into <code>dcf</code>'s <code>bytes</code>
+ * @param offset offset into {@code dcf}'s {@code bytes}
* to start parsing at
- * @param observer null-ok; parse observer to report to, if any
- * @return non-null; an appropriately-constructed {@link Attribute}
+ * @param observer {@code null-ok;} parse observer to report to, if any
+ * @return {@code non-null;} an appropriately-constructed {@link Attribute}
*/
public final Attribute parse(DirectClassFile cf, int context, int offset,
ParseObserver observer) {
@@ -108,15 +108,15 @@
* an instance of {@link RawAttribute}. Subclasses are expected to
* override this to do something better in most cases.
*
- * @param cf non-null; class file to parse from
- * @param context context to parse in; one of the <code>CTX_*</code>
+ * @param cf {@code non-null;} class file to parse from
+ * @param context context to parse in; one of the {@code CTX_*}
* constants
- * @param name non-null; the attribute name
- * @param offset offset into <code>bytes</code> to start parsing at; this
+ * @param name {@code non-null;} the attribute name
+ * @param offset offset into {@code bytes} to start parsing at; this
* is the offset to the start of attribute data, not to the header
* @param length the length of the attribute data
- * @param observer null-ok; parse observer to report to, if any
- * @return non-null; an appropriately-constructed {@link Attribute}
+ * @param observer {@code null-ok;} parse observer to report to, if any
+ * @return {@code non-null;} an appropriately-constructed {@link Attribute}
*/
protected Attribute parse0(DirectClassFile cf, int context, String name,
int offset, int length,
diff --git a/dx/src/com/android/dx/cf/direct/AttributeListParser.java b/dx/src/com/android/dx/cf/direct/AttributeListParser.java
index 7652265..2715e6a 100644
--- a/dx/src/com/android/dx/cf/direct/AttributeListParser.java
+++ b/dx/src/com/android/dx/cf/direct/AttributeListParser.java
@@ -27,7 +27,7 @@
* Parser for lists of attributes.
*/
final /*package*/ class AttributeListParser {
- /** non-null; the class file to parse from */
+ /** {@code non-null;} the class file to parse from */
private final DirectClassFile cf;
/** attribute parsing context */
@@ -36,26 +36,26 @@
/** offset in the byte array of the classfile to the start of the list */
private final int offset;
- /** non-null; attribute factory to use */
+ /** {@code non-null;} attribute factory to use */
private final AttributeFactory attributeFactory;
- /** non-null; list of parsed attributes */
+ /** {@code non-null;} list of parsed attributes */
private final StdAttributeList list;
- /** >= -1; the end offset of this list in the byte array of the
- * classfile, or <code>-1</code> if not yet parsed */
+ /** {@code >= -1;} the end offset of this list in the byte array of the
+ * classfile, or {@code -1} if not yet parsed */
private int endOffset;
- /** null-ok; parse observer, if any */
+ /** {@code null-ok;} parse observer, if any */
private ParseObserver observer;
/**
* Constructs an instance.
*
- * @param cf non-null; class file to parse from
+ * @param cf {@code non-null;} class file to parse from
* @param context attribute parsing context (see {@link AttributeFactory})
- * @param offset offset in <code>bytes</code> to the start of the list
- * @param attributeFactory non-null; attribute factory to use
+ * @param offset offset in {@code bytes} to the start of the list
+ * @param attributeFactory {@code non-null;} attribute factory to use
*/
public AttributeListParser(DirectClassFile cf, int context, int offset,
AttributeFactory attributeFactory) {
@@ -80,17 +80,17 @@
/**
* Sets the parse observer for this instance.
*
- * @param observer null-ok; the observer
+ * @param observer {@code null-ok;} the observer
*/
public void setObserver(ParseObserver observer) {
this.observer = observer;
}
/**
- * Gets the end offset of this constant pool in the <code>byte[]</code>
+ * Gets the end offset of this constant pool in the {@code byte[]}
* which it came from.
*
- * @return >= 0; the end offset
+ * @return {@code >= 0;} the end offset
*/
public int getEndOffset() {
parseIfNecessary();
@@ -100,7 +100,7 @@
/**
* Gets the parsed list.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public StdAttributeList getList() {
parseIfNecessary();
diff --git a/dx/src/com/android/dx/cf/direct/ClassPathOpener.java b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
index d302349..927e9bd 100644
--- a/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
+++ b/dx/src/com/android/dx/cf/direct/ClassPathOpener.java
@@ -36,9 +36,9 @@
*/
public class ClassPathOpener {
- /** non-null; pathname to start with */
+ /** {@code non-null;} pathname to start with */
private final String pathname;
- /** non-null; callback interface */
+ /** {@code non-null;} callback interface */
private final Consumer consumer;
/**
* If true, sort such that classes appear before their inner
@@ -48,20 +48,20 @@
private final boolean sort;
/**
- * Callback interface for <code>ClassOpener</code>.
+ * Callback interface for {@code ClassOpener}.
*/
public interface Consumer {
/**
* Provides the file name and byte array for a class path element.
*
- * @param name non-null; filename of element. May not be a valid
+ * @param name {@code non-null;} filename of element. May not be a valid
* filesystem path.
*
- * @param bytes non-null; file data
+ * @param bytes {@code non-null;} file data
* @return true on success. Result is or'd with all other results
- * from <code>processFileBytes</code> and returned to the caller
- * of <code>process()</code>.
+ * from {@code processFileBytes} and returned to the caller
+ * of {@code process()}.
*/
boolean processFileBytes(String name, byte[] bytes);
@@ -69,14 +69,14 @@
* Informs consumer that an exception occurred while processing
* this path element. Processing will continue if possible.
*
- * @param ex non-null; exception
+ * @param ex {@code non-null;} exception
*/
void onException(Exception ex);
/**
* Informs consumer that processing of an archive file has begun.
*
- * @param file non-null; archive file being processed
+ * @param file {@code non-null;} archive file being processed
*/
void onProcessArchiveStart(File file);
}
@@ -84,11 +84,11 @@
/**
* Constructs an instance.
*
- * @param pathname non-null; path element to process
+ * @param pathname {@code non-null;} path element to process
* @param sort if true, sort such that classes appear before their inner
* classes and "package-info" occurs before all other classes in that
* package.
- * @param consumer non-null; callback interface
+ * @param consumer {@code non-null;} callback interface
*/
public ClassPathOpener(String pathname, boolean sort, Consumer consumer) {
this.pathname = pathname;
@@ -100,7 +100,7 @@
* Processes a path element.
*
* @return the OR of all return values
- * from <code>Consumer.processFileBytes()</code>.
+ * from {@code Consumer.processFileBytes()}.
*/
public boolean process() {
File file = new File(pathname);
@@ -111,7 +111,7 @@
/**
* Processes one file.
*
- * @param file non-null; the file to process
+ * @param file {@code non-null;} the file to process
* @param topLevel whether this is a top-level file (that is,
* specified directly on the commandline)
* @return whether any processing actually happened
@@ -142,9 +142,9 @@
* Sorts java class names such that outer classes preceed their inner
* classes and "package-info" preceeds all other classes in its package.
*
- * @param a non-null; first class name
- * @param b non-null; second class name
- * @return <code>compareTo()</code>-style result
+ * @param a {@code non-null;} first class name
+ * @param b {@code non-null;} second class name
+ * @return {@code compareTo()}-style result
*/
private static int compareClassNames(String a, String b) {
// Ensure inner classes sort second
@@ -164,7 +164,7 @@
/**
* Processes a directory recursively.
*
- * @param dir non-null; file representing the directory
+ * @param dir {@code non-null;} file representing the directory
* @param topLevel whether this is a top-level directory (that is,
* specified directly on the commandline)
* @return whether any processing actually happened
@@ -194,10 +194,10 @@
}
/**
- * Processes the contents of an archive (<code>.zip</code>,
- * <code>.jar</code>, or <code>.apk</code>).
+ * Processes the contents of an archive ({@code .zip},
+ * {@code .jar}, or {@code .apk}).
*
- * @param file non-null; archive file to process
+ * @param file {@code non-null;} archive file to process
* @return whether any processing actually happened
* @throws IOException on i/o problem
*/
@@ -220,8 +220,7 @@
consumer.onProcessArchiveStart(file);
- for (ZipEntry one: entriesList) {
-
+ for (ZipEntry one : entriesList) {
if (one.isDirectory()) {
continue;
}
diff --git a/dx/src/com/android/dx/cf/direct/CodeObserver.java b/dx/src/com/android/dx/cf/direct/CodeObserver.java
index 950147f..952f1bc 100644
--- a/dx/src/com/android/dx/cf/direct/CodeObserver.java
+++ b/dx/src/com/android/dx/cf/direct/CodeObserver.java
@@ -39,17 +39,17 @@
* Bytecode visitor to use when "observing" bytecode getting parsed.
*/
public class CodeObserver implements BytecodeArray.Visitor {
- /** non-null; actual array of bytecode */
+ /** {@code non-null;} actual array of bytecode */
private final ByteArray bytes;
- /** non-null; observer to inform of parsing */
+ /** {@code non-null;} observer to inform of parsing */
private final ParseObserver observer;
/**
* Constructs an instance.
*
- * @param bytes non-null; actual array of bytecode
- * @param observer non-null; observer to inform of parsing
+ * @param bytes {@code non-null;} actual array of bytecode
+ * @param observer {@code non-null;} observer to inform of parsing
*/
public CodeObserver(ByteArray bytes, ParseObserver observer) {
if (bytes == null) {
@@ -218,8 +218,8 @@
}
/**
- * Helper for {code #visitConstant} where the constant is an
- * <code>int</code>.
+ * Helper for {@link #visitConstant} where the constant is an
+ * {@code int}.
*
* @param opcode the opcode
* @param offset offset to the instruction
@@ -245,8 +245,8 @@
}
/**
- * Helper for {code #visitConstant} where the constant is a
- * <code>long</code>.
+ * Helper for {@link #visitConstant} where the constant is a
+ * {@code long}.
*
* @param opcode the opcode
* @param offset offset to the instruction
@@ -269,8 +269,8 @@
}
/**
- * Helper for {code #visitConstant} where the constant is a
- * <code>float</code>.
+ * Helper for {@link #visitConstant} where the constant is a
+ * {@code float}.
*
* @param opcode the opcode
* @param offset offset to the instruction
@@ -287,8 +287,8 @@
}
/**
- * Helper for {code #visitConstant} where the constant is a
- * <code>double</code>.
+ * Helper for {@link #visitConstant} where the constant is a
+ * {@code double}.
*
* @param opcode the opcode
* @param offset offset to the instruction
diff --git a/dx/src/com/android/dx/cf/direct/DirectClassFile.java b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
index e4751a4..ac227fa 100644
--- a/dx/src/com/android/dx/cf/direct/DirectClassFile.java
+++ b/dx/src/com/android/dx/cf/direct/DirectClassFile.java
@@ -38,14 +38,14 @@
import com.android.dx.util.Hex;
/**
- * Class file with info taken from a <code>byte[]</code> or slice thereof.
+ * Class file with info taken from a {@code byte[]} or slice thereof.
*/
public class DirectClassFile implements ClassFile {
/** the expected value of the ClassFile.magic field */
private static final int CLASS_FILE_MAGIC = 0xcafebabe;
/**
- * minimum <code>.class</code> file major version
+ * minimum {@code .class} file major version
*
* The class file definition (vmspec/2nd-edition) says:
*
@@ -64,92 +64,92 @@
*/
private static final int CLASS_FILE_MIN_MAJOR_VERSION = 45;
- /** maximum <code>.class</code> file major version */
+ /** maximum {@code .class} file major version */
private static final int CLASS_FILE_MAX_MAJOR_VERSION = 50;
- /** maximum <code>.class</code> file minor version */
+ /** maximum {@code .class} file minor version */
private static final int CLASS_FILE_MAX_MINOR_VERSION = 0;
/**
- * non-null; the file path for the class, excluding any base directory
+ * {@code non-null;} the file path for the class, excluding any base directory
* specification
*/
private final String filePath;
- /** non-null; the bytes of the file */
+ /** {@code non-null;} the bytes of the file */
private final ByteArray bytes;
/**
* whether to be strict about parsing; if
- * <code>false</code>, this avoids doing checks that only exist
+ * {@code false}, this avoids doing checks that only exist
* for purposes of verification (such as magic number matching and
* path-package consistency checking)
*/
private final boolean strictParse;
/**
- * null-ok; the constant pool; only ever <code>null</code>
+ * {@code null-ok;} the constant pool; only ever {@code null}
* before the constant pool is successfully parsed
*/
private StdConstantPool pool;
/**
- * the class file field <code>access_flags</code>; will be <code>-1</code>
+ * the class file field {@code access_flags}; will be {@code -1}
* before the file is successfully parsed
*/
private int accessFlags;
/**
- * null-ok; the class file field <code>this_class</code>,
- * interpreted as a type constant; only ever <code>null</code>
+ * {@code null-ok;} the class file field {@code this_class},
+ * interpreted as a type constant; only ever {@code null}
* before the file is successfully parsed
*/
private CstType thisClass;
/**
- * null-ok; the class file field <code>super_class</code>, interpreted
+ * {@code null-ok;} the class file field {@code super_class}, interpreted
* as a type constant if non-zero
*/
private CstType superClass;
/**
- * null-ok; the class file field <code>interfaces</code>; only
- * ever <code>null</code> before the file is successfully
+ * {@code null-ok;} the class file field {@code interfaces}; only
+ * ever {@code null} before the file is successfully
* parsed
*/
private TypeList interfaces;
/**
- * null-ok; the class file field <code>fields</code>; only ever
- * <code>null</code> before the file is successfully parsed
+ * {@code null-ok;} the class file field {@code fields}; only ever
+ * {@code null} before the file is successfully parsed
*/
private FieldList fields;
/**
- * null-ok; the class file field <code>methods</code>; only ever
- * <code>null</code> before the file is successfully parsed
+ * {@code null-ok;} the class file field {@code methods}; only ever
+ * {@code null} before the file is successfully parsed
*/
private MethodList methods;
/**
- * null-ok; the class file field <code>attributes</code>; only
- * ever <code>null</code> before the file is successfully
+ * {@code null-ok;} the class file field {@code attributes}; only
+ * ever {@code null} before the file is successfully
* parsed
*/
private StdAttributeList attributes;
- /** null-ok; attribute factory, if any */
+ /** {@code null-ok;} attribute factory, if any */
private AttributeFactory attributeFactory;
- /** null-ok; parse observer, if any */
+ /** {@code null-ok;} parse observer, if any */
private ParseObserver observer;
/**
- * Returns the string form of an object or <code>"(none)"</code>
- * (rather than <code>"null"</code>) for <code>null</code>.
+ * Returns the string form of an object or {@code "(none)"}
+ * (rather than {@code "null"}) for {@code null}.
*
- * @param obj null-ok; the object to stringify
- * @return non-null; the appropriate string form
+ * @param obj {@code null-ok;} the object to stringify
+ * @return {@code non-null;} the appropriate string form
*/
public static String stringOrNone(Object obj) {
if (obj == null) {
@@ -162,11 +162,11 @@
/**
* Constructs an instance.
*
- * @param bytes non-null; the bytes of the file
- * @param filePath non-null; the file path for the class,
+ * @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
* @param strictParse whether to be strict about parsing; if
- * <code>false</code>, this avoids doing checks that only exist
+ * {@code false}, this avoids doing checks that only exist
* for purposes of verification (such as magic number matching and
* path-package consistency checking)
*/
@@ -189,11 +189,11 @@
/**
* Constructs an instance.
*
- * @param bytes non-null; the bytes of the file
- * @param filePath non-null; the file path for the class,
+ * @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
* @param strictParse whether to be strict about parsing; if
- * <code>false</code>, this avoids doing checks that only exist
+ * {@code false}, this avoids doing checks that only exist
* for purposes of verification (such as magic number matching and
* path-package consistency checking)
*/
@@ -205,7 +205,7 @@
/**
* Sets the parse observer for this instance.
*
- * @param observer null-ok; the observer
+ * @param observer {@code null-ok;} the observer
*/
public void setObserver(ParseObserver observer) {
this.observer = observer;
@@ -214,7 +214,7 @@
/**
* Sets the attribute factory to use.
*
- * @param attributeFactory non-null; the attribute factory
+ * @param attributeFactory {@code non-null;} the attribute factory
*/
public void setAttributeFactory(AttributeFactory attributeFactory) {
if (attributeFactory == null) {
@@ -227,7 +227,7 @@
/**
* Gets the {@link ByteArray} that this instance's data comes from.
*
- * @return non-null; the bytes
+ * @return {@code non-null;} the bytes
*/
public ByteArray getBytes() {
return bytes;
@@ -317,12 +317,12 @@
* list of constant pool indices for classes, which are in turn
* 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</code>.
+ * 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)
- * @return non-null; an appropriately-constructed class list
+ * @return {@code non-null;} an appropriately-constructed class list
*/
public TypeList makeTypeList(int offset, int size) {
if (size == 0) {
@@ -337,7 +337,7 @@
}
/**
- * Gets the class file field <code>magic</code>, but without doing any
+ * Gets the class file field {@code magic}, but without doing any
* checks or parsing first.
*
* @return the magic value
@@ -347,7 +347,7 @@
}
/**
- * Gets the class file field <code>minor_version</code>, but
+ * Gets the class file field {@code minor_version}, but
* without doing any checks or parsing first.
*
* @return the minor version
@@ -357,7 +357,7 @@
}
/**
- * Gets the class file field <code>major_version</code>, but
+ * Gets the class file field {@code major_version}, but
* without doing any checks or parsing first.
*
* @return the major version
@@ -554,27 +554,27 @@
* which are in turn returned as 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</code>.
+ * {@code Class}.
*/
private static class DcfTypeList implements TypeList {
- /** non-null; array containing the data */
+ /** {@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;
- /** non-null; the constant pool */
+ /** {@code non-null;} the constant pool */
private final StdConstantPool pool;
/**
* Constructs an instance.
*
- * @param bytes non-null; original classfile's bytes
+ * @param bytes {@code non-null;} original classfile's bytes
* @param offset offset into {@link #bytes} for the start of the
* data
* @param size number of elements in the list (not number of bytes)
- * @param pool non-null; the constant pool to use
- * @param observer null-ok; parse observer to use, if any
+ * @param pool {@code non-null;} the constant pool to use
+ * @param observer {@code null-ok;} parse observer to use, if any
*/
public DcfTypeList(ByteArray bytes, int offset, int size,
StdConstantPool pool, ParseObserver observer) {
diff --git a/dx/src/com/android/dx/cf/direct/FieldListParser.java b/dx/src/com/android/dx/cf/direct/FieldListParser.java
index 06dcc41..24ba7e0 100644
--- a/dx/src/com/android/dx/cf/direct/FieldListParser.java
+++ b/dx/src/com/android/dx/cf/direct/FieldListParser.java
@@ -28,16 +28,16 @@
* Parser for lists of fields in a class file.
*/
final /*package*/ class FieldListParser extends MemberListParser {
- /** non-null; list in progress */
+ /** {@code non-null;} list in progress */
private final StdFieldList fields;
/**
* Constructs an instance.
*
- * @param cf non-null; the class file to parse from
- * @param definer non-null; class being defined
- * @param offset offset in <code>bytes</code> to the start of the list
- * @param attributeFactory non-null; attribute factory to use
+ * @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
+ * @param attributeFactory {@code non-null;} attribute factory to use
*/
public FieldListParser(DirectClassFile cf, CstType definer, int offset,
AttributeFactory attributeFactory) {
@@ -48,7 +48,7 @@
/**
* Gets the parsed list.
*
- * @return non-null; the parsed list
+ * @return {@code non-null;} the parsed list
*/
public StdFieldList getList() {
parseIfNecessary();
diff --git a/dx/src/com/android/dx/cf/direct/MemberListParser.java b/dx/src/com/android/dx/cf/direct/MemberListParser.java
index 3c0bfa8..a0023c6 100644
--- a/dx/src/com/android/dx/cf/direct/MemberListParser.java
+++ b/dx/src/com/android/dx/cf/direct/MemberListParser.java
@@ -32,32 +32,32 @@
* Parser for lists of class file members (that is, fields and methods).
*/
abstract /*package*/ class MemberListParser {
- /** non-null; the class file to parse from */
+ /** {@code non-null;} the class file to parse from */
private final DirectClassFile cf;
- /** non-null; class being defined */
+ /** {@code non-null;} class being defined */
private final CstType definer;
/** offset in the byte array of the classfile to the start of the list */
private final int offset;
- /** non-null; attribute factory to use */
+ /** {@code non-null;} attribute factory to use */
private final AttributeFactory attributeFactory;
- /** >= -1; the end offset of this list in the byte array of the
- * classfile, or <code>-1</code> if not yet parsed */
+ /** {@code >= -1;} the end offset of this list in the byte array of the
+ * classfile, or {@code -1} if not yet parsed */
private int endOffset;
- /** null-ok; parse observer, if any */
+ /** {@code null-ok;} parse observer, if any */
private ParseObserver observer;
/**
* Constructs an instance.
*
- * @param cf non-null; the class file to parse from
- * @param definer non-null; class being defined
- * @param offset offset in <code>bytes</code> to the start of the list
- * @param attributeFactory non-null; attribute factory to use
+ * @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
+ * @param attributeFactory {@code non-null;} attribute factory to use
*/
public MemberListParser(DirectClassFile cf, CstType definer,
int offset, AttributeFactory attributeFactory) {
@@ -81,10 +81,10 @@
}
/**
- * Gets the end offset of this constant pool in the <code>byte[]</code>
+ * Gets the end offset of this constant pool in the {@code byte[]}
* which it came from.
*
- * @return >= 0; the end offset
+ * @return {@code >= 0;} the end offset
*/
public int getEndOffset() {
parseIfNecessary();
@@ -94,7 +94,7 @@
/**
* Sets the parse observer for this instance.
*
- * @param observer null-ok; the observer
+ * @param observer {@code null-ok;} the observer
*/
public final void setObserver(ParseObserver observer) {
this.observer = observer;
@@ -122,7 +122,7 @@
/**
* Gets the class file being defined.
*
- * @return non-null; the class
+ * @return {@code non-null;} the class
*/
protected final CstType getDefiner() {
return definer;
@@ -132,7 +132,7 @@
* Gets the human-oriented name for what this instance is parsing.
* Subclasses must override this method.
*
- * @return non-null; the human oriented name
+ * @return {@code non-null;} the human oriented name
*/
protected abstract String humanName();
@@ -141,15 +141,15 @@
* Subclasses must override this method.
*
* @param accessFlags the flags
- * @return non-null; the string form
+ * @return {@code non-null;} the string form
*/
protected abstract String humanAccessFlags(int accessFlags);
/**
- * Gets the <code>CTX_*</code> constant to use when parsing attributes.
+ * Gets the {@code CTX_*} constant to use when parsing attributes.
* Subclasses must override this method.
*
- * @return non-null; the human oriented name
+ * @return {@code non-null;} the human oriented name
*/
protected abstract int getAttributeContext();
@@ -157,11 +157,11 @@
* Sets an element in the list. Subclasses must override this method.
*
* @param n which element
- * @param accessFlags the <code>access_flags</code>
+ * @param accessFlags the {@code access_flags}
* @param nat the interpreted name and type (based on the two
- * <code>*_index</code> fields)
+ * {@code *_index} fields)
* @param attributes list of parsed attributes
- * @return non-null; the constructed member
+ * @return {@code non-null;} the constructed member
*/
protected abstract Member set(int n, int accessFlags, CstNat nat,
AttributeList attributes);
diff --git a/dx/src/com/android/dx/cf/direct/MethodListParser.java b/dx/src/com/android/dx/cf/direct/MethodListParser.java
index 9ca8ba6..6ab1aba 100644
--- a/dx/src/com/android/dx/cf/direct/MethodListParser.java
+++ b/dx/src/com/android/dx/cf/direct/MethodListParser.java
@@ -28,16 +28,16 @@
* Parser for lists of methods in a class file.
*/
final /*package*/ class MethodListParser extends MemberListParser {
- /** non-null; list in progress */
+ /** {@code non-null;} list in progress */
final private StdMethodList methods;
/**
* Constructs an instance.
*
- * @param cf non-null; the class file to parse from
- * @param definer non-null; class being defined
- * @param offset offset in <code>bytes</code> to the start of the list
- * @param attributeFactory non-null; attribute factory to use
+ * @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
+ * @param attributeFactory {@code non-null;} attribute factory to use
*/
public MethodListParser(DirectClassFile cf, CstType definer,
int offset, AttributeFactory attributeFactory) {
@@ -48,7 +48,7 @@
/**
* Gets the parsed list.
*
- * @return non-null; the parsed list
+ * @return {@code non-null;} the parsed list
*/
public StdMethodList getList() {
parseIfNecessary();
diff --git a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
index ab0e2f7..da12a4e 100644
--- a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
+++ b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
@@ -65,7 +65,7 @@
*/
public class StdAttributeFactory
extends AttributeFactory {
- /** non-null; shared instance of this class */
+ /** {@code non-null;} shared instance of this class */
public static final StdAttributeFactory THE_ONE =
new StdAttributeFactory();
@@ -191,7 +191,7 @@
}
/**
- * Parses an <code>AnnotationDefault</code> attribute.
+ * Parses an {@code AnnotationDefault} attribute.
*/
private Attribute annotationDefault(DirectClassFile cf,
int offset, int length, ParseObserver observer) {
@@ -207,7 +207,7 @@
}
/**
- * Parses a <code>Code</code> attribute.
+ * Parses a {@code Code} attribute.
*/
private Attribute code(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -311,7 +311,7 @@
}
/**
- * Parses a <code>ConstantValue</code> attribute.
+ * Parses a {@code ConstantValue} attribute.
*/
private Attribute constantValue(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -333,7 +333,7 @@
}
/**
- * Parses a <code>Deprecated</code> attribute.
+ * Parses a {@code Deprecated} attribute.
*/
private Attribute deprecated(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -345,7 +345,7 @@
}
/**
- * Parses an <code>EnclosingMethod</code> attribute.
+ * Parses an {@code EnclosingMethod} attribute.
*/
private Attribute enclosingMethod(DirectClassFile cf, int offset,
int length, ParseObserver observer) {
@@ -374,7 +374,7 @@
}
/**
- * Parses an <code>Exceptions</code> attribute.
+ * Parses an {@code Exceptions} attribute.
*/
private Attribute exceptions(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -402,7 +402,7 @@
}
/**
- * Parses an <code>InnerClasses</code> attribute.
+ * Parses an {@code InnerClasses} attribute.
*/
private Attribute innerClasses(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -459,7 +459,7 @@
}
/**
- * Parses a <code>LineNumberTable</code> attribute.
+ * Parses a {@code LineNumberTable} attribute.
*/
private Attribute lineNumberTable(DirectClassFile cf, int offset,
int length, ParseObserver observer) {
@@ -500,7 +500,7 @@
}
/**
- * Parses a <code>LocalVariableTable</code> attribute.
+ * Parses a {@code LocalVariableTable} attribute.
*/
private Attribute localVariableTable(DirectClassFile cf, int offset,
int length, ParseObserver observer) {
@@ -523,7 +523,7 @@
}
/**
- * Parses a <code>LocalVariableTypeTable</code> attribute.
+ * Parses a {@code LocalVariableTypeTable} attribute.
*/
private Attribute localVariableTypeTable(DirectClassFile cf, int offset,
int length, ParseObserver observer) {
@@ -546,15 +546,15 @@
}
/**
- * Parse the table part of either a <code>LocalVariableTable</code>
- * or a <code>LocalVariableTypeTable</code>.
+ * Parse the table part of either a {@code LocalVariableTable}
+ * or a {@code LocalVariableTypeTable}.
*
- * @param bytes non-null; bytes to parse, which should <i>only</i>
+ * @param bytes {@code non-null;} bytes to parse, which should <i>only</i>
* contain the table data (no header)
- * @param pool non-null; constant pool to use
- * @param count >= 0; the number of entries
- * @param typeTable <code>true</code> iff this is for a type table
- * @return non-null; the constructed list
+ * @param pool {@code non-null;} constant pool to use
+ * @param count {@code >= 0;} the number of entries
+ * @param typeTable {@code true} iff this is for a type table
+ * @return {@code non-null;} the constructed list
*/
private LocalVariableList parseLocalVariables(ByteArray bytes,
ConstantPool pool, ParseObserver observer, int count,
@@ -604,7 +604,7 @@
}
/**
- * Parses a <code>RuntimeInvisibleAnnotations</code> attribute.
+ * Parses a {@code RuntimeInvisibleAnnotations} attribute.
*/
private Attribute runtimeInvisibleAnnotations(DirectClassFile cf,
int offset, int length, ParseObserver observer) {
@@ -621,7 +621,7 @@
}
/**
- * Parses a <code>RuntimeVisibleAnnotations</code> attribute.
+ * Parses a {@code RuntimeVisibleAnnotations} attribute.
*/
private Attribute runtimeVisibleAnnotations(DirectClassFile cf,
int offset, int length, ParseObserver observer) {
@@ -638,7 +638,7 @@
}
/**
- * Parses a <code>RuntimeInvisibleParameterAnnotations</code> attribute.
+ * Parses a {@code RuntimeInvisibleParameterAnnotations} attribute.
*/
private Attribute runtimeInvisibleParameterAnnotations(DirectClassFile cf,
int offset, int length, ParseObserver observer) {
@@ -655,7 +655,7 @@
}
/**
- * Parses a <code>RuntimeVisibleParameterAnnotations</code> attribute.
+ * Parses a {@code RuntimeVisibleParameterAnnotations} attribute.
*/
private Attribute runtimeVisibleParameterAnnotations(DirectClassFile cf,
int offset, int length, ParseObserver observer) {
@@ -672,7 +672,7 @@
}
/**
- * Parses a <code>Signature</code> attribute.
+ * Parses a {@code Signature} attribute.
*/
private Attribute signature(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -694,7 +694,7 @@
}
/**
- * Parses a <code>SourceFile</code> attribute.
+ * Parses a {@code SourceFile} attribute.
*/
private Attribute sourceFile(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
@@ -716,7 +716,7 @@
}
/**
- * Parses a <code>Synthetic</code> attribute.
+ * Parses a {@code Synthetic} attribute.
*/
private Attribute synthetic(DirectClassFile cf, int offset, int length,
ParseObserver observer) {
diff --git a/dx/src/com/android/dx/cf/iface/Attribute.java b/dx/src/com/android/dx/cf/iface/Attribute.java
index f28f51e..b075251 100644
--- a/dx/src/com/android/dx/cf/iface/Attribute.java
+++ b/dx/src/com/android/dx/cf/iface/Attribute.java
@@ -23,16 +23,16 @@
/**
* Get the name of the attribute.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public String getName();
/**
* Get the total length of the attribute in bytes, including the
* header. Since the header is always six bytes, the result of
- * this method is always at least <code>6</code>.
+ * this method is always at least {@code 6}.
*
- * @return >= 6; the total length, in bytes
+ * @return {@code >= 6;} the total length, in bytes
*/
public int byteLength();
}
diff --git a/dx/src/com/android/dx/cf/iface/AttributeList.java b/dx/src/com/android/dx/cf/iface/AttributeList.java
index a72965a..f7a1d27 100644
--- a/dx/src/com/android/dx/cf/iface/AttributeList.java
+++ b/dx/src/com/android/dx/cf/iface/AttributeList.java
@@ -22,11 +22,11 @@
public interface AttributeList {
/**
* Get whether this instance is mutable. Note that the
- * <code>AttributeList</code> interface itself doesn't provide any means
+ * {@code AttributeList} interface itself doesn't provide any means
* of mutation, but that doesn't mean that there isn't a non-interface
* way of mutating an instance.
*
- * @return <code>true</code> iff this instance is somehow mutable
+ * @return {@code true} iff this instance is somehow mutable
*/
public boolean isMutable();
@@ -38,28 +38,28 @@
public int size();
/**
- * Get the <code>n</code>th attribute.
+ * Get the {@code n}th attribute.
*
- * @param n <code>n >= 0, n < size()</code>; which attribute
- * @return non-null; the attribute in question
+ * @param n {@code n >= 0, n < size();} which attribute
+ * @return {@code non-null;} the attribute in question
*/
public Attribute get(int n);
/**
* Get the total length of this list in bytes, when part of a
* class file. The returned value includes the two bytes for the
- * <code>attributes_count</code> length indicator.
+ * {@code attributes_count} length indicator.
*
- * @return >= 2; the total length, in bytes
+ * @return {@code >= 2;} the total length, in bytes
*/
public int byteLength();
/**
* Get the first attribute in the list with the given name, if any.
*
- * @param name non-null; attribute name
- * @return null-ok; first attribute in the list with the given name,
- * or <code>null</code> if there is none
+ * @param name {@code non-null;} attribute name
+ * @return {@code null-ok;} first attribute in the list with the given name,
+ * or {@code null} if there is none
*/
public Attribute findFirst(String name);
@@ -67,9 +67,9 @@
* Get the next attribute in the list after the given one, with the same
* name, if any.
*
- * @param attrib non-null; attribute to start looking after
- * @return null-ok; next attribute after <code>attrib</code> with the
- * same name as <code>attrib</code>
+ * @param attrib {@code non-null;} attribute to start looking after
+ * @return {@code null-ok;} next attribute after {@code attrib} with the
+ * same name as {@code attrib}
*/
public Attribute findNext(Attribute attrib);
}
diff --git a/dx/src/com/android/dx/cf/iface/ClassFile.java b/dx/src/com/android/dx/cf/iface/ClassFile.java
index 36a5f74..e37fec0 100644
--- a/dx/src/com/android/dx/cf/iface/ClassFile.java
+++ b/dx/src/com/android/dx/cf/iface/ClassFile.java
@@ -26,98 +26,98 @@
* facsimiles thereof.
*
* <p><b>Note:</b> The fields referred to in this documentation are of the
- * <code>ClassFile</code> structure defined in vmspec-2 sec4.1.
+ * {@code ClassFile} structure defined in vmspec-2 sec4.1.
*/
public interface ClassFile {
/**
- * Gets the field <code>magic</code>.
+ * Gets the field {@code magic}.
*
* @return the value in question
*/
public int getMagic();
/**
- * Gets the field <code>minor_version</code>.
+ * Gets the field {@code minor_version}.
*
* @return the value in question
*/
public int getMinorVersion();
/**
- * Gets the field <code>major_version</code>.
+ * Gets the field {@code major_version}.
*
* @return the value in question
*/
public int getMajorVersion();
/**
- * Gets the field <code>access_flags</code>.
+ * Gets the field {@code access_flags}.
*
* @return the value in question
*/
public int getAccessFlags();
/**
- * Gets the field <code>this_class</code>, interpreted as a type constant.
+ * Gets the field {@code this_class}, interpreted as a type constant.
*
- * @return non-null; the value in question
+ * @return {@code non-null;} the value in question
*/
public CstType getThisClass();
/**
- * Gets the field <code>super_class</code>, interpreted as a type constant
+ * Gets the field {@code super_class}, interpreted as a type constant
* if non-zero.
*
- * @return null-ok; the value in question
+ * @return {@code null-ok;} the value in question
*/
public CstType getSuperclass();
/**
- * Gets the field <code>constant_pool</code> (along with
- * <code>constant_pool_count</code>).
+ * Gets the field {@code constant_pool} (along with
+ * {@code constant_pool_count}).
*
- * @return non-null; the constant pool
+ * @return {@code non-null;} the constant pool
*/
public ConstantPool getConstantPool();
/**
- * Gets the field <code>interfaces<code> (along with
- * interfaces_count</code>).
+ * Gets the field {@code interfaces} (along with
+ * {@code interfaces_count}).
*
- * @return non-null; the list of interfaces
+ * @return {@code non-null;} the list of interfaces
*/
public TypeList getInterfaces();
/**
- * Gets the field <code>fields</code> (along with
- * <code>fields_count</code>).
+ * Gets the field {@code fields} (along with
+ * {@code fields_count}).
*
- * @return non-null; the list of fields
+ * @return {@code non-null;} the list of fields
*/
public FieldList getFields();
/**
- * Gets the field <code>methods</code> (along with
- * <code>methods_count</code>).
+ * Gets the field {@code methods} (along with
+ * {@code methods_count}).
*
- * @return non-null; the list of fields
+ * @return {@code non-null;} the list of fields
*/
public MethodList getMethods();
/**
- * Gets the field <code>attributes</code> (along with
- * <code>attributes_count</code>).
+ * Gets the field {@code attributes} (along with
+ * {@code attributes_count}).
*
- * @return non-null; the list of attributes
+ * @return {@code non-null;} the list of attributes
*/
public AttributeList getAttributes();
/**
- * Gets the name out of the <code>SourceFile</code> attribute of this
+ * Gets the name out of the {@code SourceFile} attribute of this
* file, if any. This is a convenient shorthand for scrounging around
* the class's attributes.
*
- * @return non-null; the constant pool
+ * @return {@code non-null;} the constant pool
*/
public CstUtf8 getSourceFile();
}
diff --git a/dx/src/com/android/dx/cf/iface/Field.java b/dx/src/com/android/dx/cf/iface/Field.java
index d1694fc..e3002bc 100644
--- a/dx/src/com/android/dx/cf/iface/Field.java
+++ b/dx/src/com/android/dx/cf/iface/Field.java
@@ -25,10 +25,10 @@
extends Member {
/**
* Get the constant value for this field, if any. This only returns
- * non-<code>null</code> for a <code>static final</code> field which
- * includes a <code>ConstantValue</code> attribute.
+ * non-{@code null} for a {@code static final} field which
+ * includes a {@code ConstantValue} attribute.
*
- * @return null-ok; the constant value, or <code>null</code> if this
+ * @return {@code null-ok;} the constant value, or {@code null} if this
* field isn't a constant
*/
public TypedConstant getConstantValue();
diff --git a/dx/src/com/android/dx/cf/iface/FieldList.java b/dx/src/com/android/dx/cf/iface/FieldList.java
index 80a794f..9cd27a3 100644
--- a/dx/src/com/android/dx/cf/iface/FieldList.java
+++ b/dx/src/com/android/dx/cf/iface/FieldList.java
@@ -23,11 +23,11 @@
{
/**
* Get whether this instance is mutable. Note that the
- * <code>FieldList</code> interface itself doesn't provide any means
+ * {@code FieldList} interface itself doesn't provide any means
* of mutation, but that doesn't mean that there isn't a non-interface
* way of mutating an instance.
*
- * @return <code>true</code> iff this instance is somehow mutable
+ * @return {@code true} iff this instance is somehow mutable
*/
public boolean isMutable();
@@ -39,10 +39,10 @@
public int size();
/**
- * Get the <code>n</code>th field.
+ * Get the {@code n}th field.
*
- * @param n <code>n >= 0, n < size()</code>; which field
- * @return non-null; the field in question
+ * @param n {@code n >= 0, n < size();} which field
+ * @return {@code non-null;} the field in question
*/
public Field get(int n);
}
diff --git a/dx/src/com/android/dx/cf/iface/Member.java b/dx/src/com/android/dx/cf/iface/Member.java
index b305e09..0453a6f 100644
--- a/dx/src/com/android/dx/cf/iface/Member.java
+++ b/dx/src/com/android/dx/cf/iface/Member.java
@@ -27,48 +27,48 @@
/**
* Get the defining class.
*
- * @return non-null; the defining class
+ * @return {@code non-null;} the defining class
*/
public CstType getDefiningClass();
/**
- * Get the field <code>access_flags</code>.
+ * Get the field {@code access_flags}.
*
* @return the access flags
*/
public int getAccessFlags();
/**
- * Get the field <code>name_index</code> of the member. This is
- * just a convenient shorthand for <code>getNat().getName()</code>.
+ * Get the field {@code name_index} of the member. This is
+ * just a convenient shorthand for {@code getNat().getName()}.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public CstUtf8 getName();
/**
- * Get the field <code>descriptor_index</code> of the member. This is
- * just a convenient shorthand for <code>getNat().getDescriptor()</code>.
+ * Get the field {@code descriptor_index} of the member. This is
+ * just a convenient shorthand for {@code getNat().getDescriptor()}.
*
- * @return non-null; the descriptor
+ * @return {@code non-null;} the descriptor
*/
public CstUtf8 getDescriptor();
/**
* Get the name and type associated with this member. This is a
- * combination of the fields <code>name_index</code> and
- * <code>descriptor_index</code> in the original classfile, interpreted
+ * combination of the fields {@code name_index} and
+ * {@code descriptor_index} in the original classfile, interpreted
* via the constant pool.
*
- * @return non-null; the name and type
+ * @return {@code non-null;} the name and type
*/
public CstNat getNat();
/**
- * Get the field <code>attributes</code> (along with
- * <code>attributes_count</code>).
+ * Get the field {@code attributes} (along with
+ * {@code attributes_count}).
*
- * @return non-null; the constant pool
+ * @return {@code non-null;} the constant pool
*/
public AttributeList getAttributes();
}
diff --git a/dx/src/com/android/dx/cf/iface/Method.java b/dx/src/com/android/dx/cf/iface/Method.java
index 424400a..18b9af6 100644
--- a/dx/src/com/android/dx/cf/iface/Method.java
+++ b/dx/src/com/android/dx/cf/iface/Method.java
@@ -26,9 +26,9 @@
{
/**
* Get the <i>effective</i> method descriptor, which includes, if
- * necessary, a first <code>this</code> parameter.
+ * necessary, a first {@code this} parameter.
*
- * @return non-null; the effective method descriptor
+ * @return {@code non-null;} the effective method descriptor
*/
public Prototype getEffectiveDescriptor();
}
diff --git a/dx/src/com/android/dx/cf/iface/MethodList.java b/dx/src/com/android/dx/cf/iface/MethodList.java
index a7a395c..dfa6528 100644
--- a/dx/src/com/android/dx/cf/iface/MethodList.java
+++ b/dx/src/com/android/dx/cf/iface/MethodList.java
@@ -22,11 +22,11 @@
public interface MethodList {
/**
* Get whether this instance is mutable. Note that the
- * <code>MethodList</code> interface itself doesn't provide any means
+ * {@code MethodList} interface itself doesn't provide any means
* of mutation, but that doesn't mean that there isn't a non-interface
* way of mutating an instance.
*
- * @return <code>true</code> iff this instance is somehow mutable
+ * @return {@code true} iff this instance is somehow mutable
*/
public boolean isMutable();
@@ -38,10 +38,10 @@
public int size();
/**
- * Get the <code>n</code>th method.
+ * Get the {@code n}th method.
*
- * @param n <code>n >= 0, n < size()</code>; which method
- * @return non-null; the method in question
+ * @param n {@code n >= 0, n < size();} which method
+ * @return {@code non-null;} the method in question
*/
public Method get(int n);
}
diff --git a/dx/src/com/android/dx/cf/iface/ParseObserver.java b/dx/src/com/android/dx/cf/iface/ParseObserver.java
index 2ad3493..98d5a75 100644
--- a/dx/src/com/android/dx/cf/iface/ParseObserver.java
+++ b/dx/src/com/android/dx/cf/iface/ParseObserver.java
@@ -34,11 +34,11 @@
/**
* Indicate that a particular member is now being parsed.
*
- * @param bytes non-null; the source that is being parsed
- * @param offset offset into <code>bytes</code> for the start of the
+ * @param bytes {@code non-null;} the source that is being parsed
+ * @param offset offset into {@code bytes} for the start of the
* member
- * @param name non-null; name of the member
- * @param descriptor non-null; descriptor of the member
+ * @param name {@code non-null;} name of the member
+ * @param descriptor {@code non-null;} descriptor of the member
*/
public void startParsingMember(ByteArray bytes, int offset, String name,
String descriptor);
@@ -46,12 +46,12 @@
/**
* Indicate that a particular member is no longer being parsed.
*
- * @param bytes non-null; the source that was parsed
- * @param offset offset into <code>bytes</code> for the end of the
+ * @param bytes {@code non-null;} the source that was parsed
+ * @param offset offset into {@code bytes} for the end of the
* member
- * @param name non-null; name of the member
- * @param descriptor non-null; descriptor of the member
- * @param member non-null; the actual member that was parsed
+ * @param name {@code non-null;} name of the member
+ * @param descriptor {@code non-null;} descriptor of the member
+ * @param member {@code non-null;} the actual member that was parsed
*/
public void endParsingMember(ByteArray bytes, int offset, String name,
String descriptor, Member member);
@@ -59,10 +59,10 @@
/**
* Indicate that some parsing happened.
*
- * @param bytes non-null; the source that was parsed
- * @param offset offset into <code>bytes</code> for what was parsed
+ * @param bytes {@code non-null;} the source that was parsed
+ * @param offset offset into {@code bytes} for what was parsed
* @param len number of bytes parsed
- * @param human non-null; human form for what was parsed
+ * @param human {@code non-null;} human form for what was parsed
*/
public void parsed(ByteArray bytes, int offset, int len, String human);
}
diff --git a/dx/src/com/android/dx/cf/iface/StdAttributeList.java b/dx/src/com/android/dx/cf/iface/StdAttributeList.java
index c29bb08..dd5dfd7 100644
--- a/dx/src/com/android/dx/cf/iface/StdAttributeList.java
+++ b/dx/src/com/android/dx/cf/iface/StdAttributeList.java
@@ -25,7 +25,7 @@
public final class StdAttributeList extends FixedSizeList
implements AttributeList {
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -95,8 +95,8 @@
/**
* Sets the attribute at the given index.
*
- * @param n >= 0, < size(); which attribute
- * @param attribute null-ok; the attribute object
+ * @param n {@code >= 0, < size();} which attribute
+ * @param attribute {@code null-ok;} the attribute object
*/
public void set(int n, Attribute attribute) {
set0(n, attribute);
diff --git a/dx/src/com/android/dx/cf/iface/StdField.java b/dx/src/com/android/dx/cf/iface/StdField.java
index 3551aee..c3a4da6 100644
--- a/dx/src/com/android/dx/cf/iface/StdField.java
+++ b/dx/src/com/android/dx/cf/iface/StdField.java
@@ -29,10 +29,10 @@
/**
* Constructs an instance.
*
- * @param definingClass non-null; the defining class
+ * @param definingClass {@code non-null;} the defining class
* @param accessFlags access flags
- * @param nat non-null; member name and type (descriptor)
- * @param attributes non-null; list of associated attributes
+ * @param nat {@code non-null;} member name and type (descriptor)
+ * @param attributes {@code non-null;} list of associated attributes
*/
public StdField(CstType definingClass, int accessFlags, CstNat nat,
AttributeList attributes) {
diff --git a/dx/src/com/android/dx/cf/iface/StdFieldList.java b/dx/src/com/android/dx/cf/iface/StdFieldList.java
index 0f8654b..044d6b7 100644
--- a/dx/src/com/android/dx/cf/iface/StdFieldList.java
+++ b/dx/src/com/android/dx/cf/iface/StdFieldList.java
@@ -24,7 +24,7 @@
*/
public final class StdFieldList extends FixedSizeList implements FieldList {
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -40,8 +40,8 @@
/**
* Sets the field at the given index.
*
- * @param n >= 0, < size(); which field
- * @param field null-ok; the field object
+ * @param n {@code >= 0, < size();} which field
+ * @param field {@code null-ok;} the field object
*/
public void set(int n, Field field) {
set0(n, field);
diff --git a/dx/src/com/android/dx/cf/iface/StdMember.java b/dx/src/com/android/dx/cf/iface/StdMember.java
index eaf949e..dfe45c3 100644
--- a/dx/src/com/android/dx/cf/iface/StdMember.java
+++ b/dx/src/com/android/dx/cf/iface/StdMember.java
@@ -25,25 +25,25 @@
* all the associated data.
*/
public abstract class StdMember implements Member {
- /** non-null; the defining class */
+ /** {@code non-null;} the defining class */
private final CstType definingClass;
/** access flags */
private final int accessFlags;
- /** non-null; member name and type */
+ /** {@code non-null;} member name and type */
private final CstNat nat;
- /** non-null; list of associated attributes */
+ /** {@code non-null;} list of associated attributes */
private final AttributeList attributes;
/**
* Constructs an instance.
*
- * @param definingClass non-null; the defining class
+ * @param definingClass {@code non-null;} the defining class
* @param accessFlags access flags
- * @param nat non-null; member name and type (descriptor)
- * @param attributes non-null; list of associated attributes
+ * @param nat {@code non-null;} member name and type (descriptor)
+ * @param attributes {@code non-null;} list of associated attributes
*/
public StdMember(CstType definingClass, int accessFlags, CstNat nat,
AttributeList attributes) {
diff --git a/dx/src/com/android/dx/cf/iface/StdMethod.java b/dx/src/com/android/dx/cf/iface/StdMethod.java
index a4acbaa..15fd6e1 100644
--- a/dx/src/com/android/dx/cf/iface/StdMethod.java
+++ b/dx/src/com/android/dx/cf/iface/StdMethod.java
@@ -26,16 +26,16 @@
* all the associated data.
*/
public final class StdMethod extends StdMember implements Method {
- /** non-null; the effective method descriptor */
+ /** {@code non-null;} the effective method descriptor */
private final Prototype effectiveDescriptor;
/**
* Constructs an instance.
*
- * @param definingClass non-null; the defining class
+ * @param definingClass {@code non-null;} the defining class
* @param accessFlags access flags
- * @param nat non-null; member name and type (descriptor)
- * @param attributes non-null; list of associated attributes
+ * @param nat {@code non-null;} member name and type (descriptor)
+ * @param attributes {@code non-null;} list of associated attributes
*/
public StdMethod(CstType definingClass, int accessFlags, CstNat nat,
AttributeList attributes) {
diff --git a/dx/src/com/android/dx/cf/iface/StdMethodList.java b/dx/src/com/android/dx/cf/iface/StdMethodList.java
index ef0ff31..521021e 100644
--- a/dx/src/com/android/dx/cf/iface/StdMethodList.java
+++ b/dx/src/com/android/dx/cf/iface/StdMethodList.java
@@ -24,7 +24,7 @@
*/
public final class StdMethodList extends FixedSizeList implements MethodList {
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -40,8 +40,8 @@
/**
* Sets the method at the given index.
*
- * @param n >= 0, < size(); which method
- * @param method null-ok; the method object
+ * @param n {@code >= 0, < size();} which method
+ * @param method {@code null-ok;} the method object
*/
public void set(int n, Method method) {
set0(n, method);
diff --git a/dx/src/com/android/dx/command/DxConsole.java b/dx/src/com/android/dx/command/DxConsole.java
index 982e659..9ce9836 100644
--- a/dx/src/com/android/dx/command/DxConsole.java
+++ b/dx/src/com/android/dx/command/DxConsole.java
@@ -20,18 +20,18 @@
/**
* Provides standard and error PrintStream object to output information.<br>
- * By default the PrintStream objects link to <code>System.out</code> and
- * <code>System.err</code> but they can be changed to link to other
+ * By default the PrintStream objects link to {@code System.out} and
+ * {@code System.err} but they can be changed to link to other
* PrintStream.
*/
public class DxConsole {
/**
- * Standard output stream. Links to <code>System.out</code> by default.
+ * Standard output stream. Links to {@code System.out} by default.
*/
public static PrintStream out = System.out;
/**
- * Error output stream. Links to <code>System.err</code> by default.
+ * Error output stream. Links to {@code System.err} by default.
*/
public static PrintStream err = System.err;
}
diff --git a/dx/src/com/android/dx/command/Main.java b/dx/src/com/android/dx/command/Main.java
index 17f5db3..281a83e 100644
--- a/dx/src/com/android/dx/command/Main.java
+++ b/dx/src/com/android/dx/command/Main.java
@@ -43,10 +43,12 @@
" options: none, important, lines.\n" +
" dx --annotool --annotation=<class> [--element=<element types>]\n" +
" [--print=<print types>]\n" +
- " dx --dump [--debug] [--strict] [--bytes] [--basic-blocks | " +
- "--rop-blocks]\n" +
+ " dx --dump [--debug] [--strict] [--bytes] [--optimize]\n" +
+ " [--basic-blocks | --rop-blocks | --ssa-blocks | --dot] " +
+ "[--ssa-step=<step>]\n" +
" [--width=<n>] [<file>.class | <file>.txt] ...\n" +
- " Dump classfiles in a human-oriented format.\n" +
+ " Dump classfiles, or transformations thereof, in a " +
+ "human-oriented format.\n" +
" dx --junit [-wait] <TestClass>\n" +
" Run the indicated unit test.\n" +
" dx -J<option> ... <arguments, in one of the above " +
@@ -156,9 +158,9 @@
* Returns a copy of the given args array, but without the indicated
* element.
*
- * @param orig non-null; original array
+ * @param orig {@code non-null;} original array
* @param n which element to omit
- * @return non-null; new array
+ * @return {@code non-null;} new array
*/
private static String[] without(String[] orig, int n) {
int len = orig.length - 1;
diff --git a/dx/src/com/android/dx/command/annotool/AnnotationLister.java b/dx/src/com/android/dx/command/annotool/AnnotationLister.java
index 78f5d64..d3fb27c 100644
--- a/dx/src/com/android/dx/command/annotool/AnnotationLister.java
+++ b/dx/src/com/android/dx/command/annotool/AnnotationLister.java
@@ -34,10 +34,9 @@
/**
* Greps annotations on a set of class files and prints matching elements
* to stdout. What counts as a match and what should be printed is controlled
- * by the <code>Main.Arguments</code> instance.
+ * by the {@code Main.Arguments} instance.
*/
class AnnotationLister {
-
/**
* The string name of the pseudo-class that
* contains package-wide annotations
@@ -59,7 +58,7 @@
/** Processes based on configuration specified in constructor. */
void process() {
- for (String path: args.files) {
+ for (String path : args.files) {
ClassPathOpener opener;
opener = new ClassPathOpener(path, true,
@@ -137,8 +136,8 @@
/**
* Inspects a class annotation.
*
- * @param cf non-null; class file
- * @param ann non-null; annotation
+ * @param cf {@code non-null;} class file
+ * @param ann {@code non-null;} annotation
*/
private void visitClassAnnotation(DirectClassFile cf,
BaseAnnotations ann) {
@@ -147,7 +146,7 @@
return;
}
- for (Annotation anAnn: ann.getAnnotations().getAnnotations()) {
+ for (Annotation anAnn : ann.getAnnotations().getAnnotations()) {
String annClassName
= anAnn.getType().getClassType().getClassName();
if (args.aclass.equals(annClassName)) {
@@ -159,8 +158,8 @@
/**
* Inspects a package annotation
*
- * @param cf non-null; class file of "package-info" pseudo-class
- * @param ann non-null; annotation
+ * @param cf {@code non-null;} class file of "package-info" pseudo-class
+ * @param ann {@code non-null;} annotation
*/
private void visitPackageAnnotation(
DirectClassFile cf, BaseAnnotations ann) {
@@ -181,7 +180,7 @@
}
- for (Annotation anAnn: ann.getAnnotations().getAnnotations()) {
+ for (Annotation anAnn : ann.getAnnotations().getAnnotations()) {
String annClassName
= anAnn.getType().getClassType().getClassName();
if (args.aclass.equals(annClassName)) {
@@ -195,10 +194,10 @@
* Prints, or schedules for printing, elements related to a
* matching package.
*
- * @param packageName non-null; name of package
+ * @param packageName {@code non-null;} name of package
*/
private void printMatchPackage(String packageName) {
- for(Main.PrintType pt: args.printTypes) {
+ for (Main.PrintType pt : args.printTypes) {
switch (pt) {
case CLASS:
case INNERCLASS:
@@ -216,14 +215,15 @@
* Prints, or schedules for printing, elements related to a matching
* class.
*
- * @param cf non-null; matching class
+ * @param cf {@code non-null;} matching class
*/
private void printMatch(DirectClassFile cf) {
- for(Main.PrintType pt: args.printTypes) {
+ for (Main.PrintType pt : args.printTypes) {
switch (pt) {
case CLASS:
String classname;
- classname = cf.getThisClass().getClassType().getClassName();
+ classname =
+ cf.getThisClass().getClassType().getClassName();
classname = classname.replace('/','.');
System.out.println(classname);
break;
@@ -244,7 +244,7 @@
* Checks to see if a specified class name should be considered a match
* due to previous matches.
*
- * @param s non-null; class name
+ * @param s {@code non-null;} class name
* @return true if this class should be considered a match
*/
private boolean isMatchingInnerClass(String s) {
@@ -264,7 +264,7 @@
* Checks to see if a specified package should be considered a match due
* to previous matches.
*
- * @param s non-null; package name
+ * @param s {@code non-null;} package name
* @return true if this package should be considered a match
*/
private boolean isMatchingPackage(String s) {
diff --git a/dx/src/com/android/dx/command/annotool/Main.java b/dx/src/com/android/dx/command/annotool/Main.java
index 4f1d9a4..9fd1ac5 100644
--- a/dx/src/com/android/dx/command/annotool/Main.java
+++ b/dx/src/com/android/dx/command/annotool/Main.java
@@ -87,17 +87,18 @@
String argParam = arg.substring(arg.indexOf('=') + 1);
try {
- for (String p: argParam.split(",")) {
+ for (String p : argParam.split(",")) {
eTypes.add(ElementType.valueOf(p.toUpperCase()));
}
} catch (IllegalArgumentException ex) {
- throw new InvalidArgumentException("invalid --element");
+ throw new InvalidArgumentException(
+ "invalid --element");
}
} else if (arg.startsWith("--print=")) {
String argParam = arg.substring(arg.indexOf('=') + 1);
try {
- for (String p: argParam.split(",")) {
+ for (String p : argParam.split(",")) {
printTypes.add(PrintType.valueOf(p.toUpperCase()));
}
} catch (IllegalArgumentException ex) {
diff --git a/dx/src/com/android/dx/command/dexer/Main.java b/dx/src/com/android/dx/command/dexer/Main.java
index 19f67b4..5a9f417 100644
--- a/dx/src/com/android/dx/command/dexer/Main.java
+++ b/dx/src/com/android/dx/command/dexer/Main.java
@@ -55,26 +55,26 @@
*/
public class Main {
/**
- * non-null; name for the <code>.dex</code> file that goes into
- * <code>.jar</code> files
+ * {@code non-null;} name for the {@code .dex} file that goes into
+ * {@code .jar} files
*/
private static final String DEX_IN_JAR_NAME = "classes.dex";
/**
- * non-null; name of the standard manifest file in <code>.jar</code>
+ * {@code non-null;} name of the standard manifest file in {@code .jar}
* files
*/
private static final String MANIFEST_NAME = "META-INF/MANIFEST.MF";
/**
- * non-null; attribute name for the (quasi-standard?)
- * <code>Created-By</code> attribute
+ * {@code non-null;} attribute name for the (quasi-standard?)
+ * {@code Created-By} attribute
*/
private static final Attributes.Name CREATED_BY =
new Attributes.Name("Created-By");
/**
- * non-null; list of <code>javax</code> subpackages that are considered
+ * {@code non-null;} list of {@code javax} subpackages that are considered
* to be "core". <b>Note:</b>: This list must be sorted, since it
* is binary-searched.
*/
@@ -90,15 +90,15 @@
/** number of errors during processing */
private static int errors = 0;
- /** non-null; parsed command-line arguments */
+ /** {@code non-null;} parsed command-line arguments */
private static Arguments args;
- /** non-null; output file in-progress */
+ /** {@code non-null;} output file in-progress */
private static DexFile outputDex;
/**
- * null-ok; map of resources to include in the output, or
- * <code>null</code> if resources are being ignored
+ * {@code null-ok;} map of resources to include in the output, or
+ * {@code null} if resources are being ignored
*/
private static TreeMap<String, byte[]> outputResources;
@@ -215,8 +215,9 @@
/**
* Processes one pathname element.
*
- * @param pathname non-null; the pathname to process. May be the path of
- * a class file, a jar file, or a directory containing class files.
+ * @param pathname {@code non-null;} the pathname to process. May
+ * be the path of a class file, a jar file, or a directory
+ * containing class files.
* @return whether any processing actually happened
*/
private static boolean processOne(String pathname) {
@@ -237,7 +238,8 @@
}
public void onProcessArchiveStart(File file) {
if (args.verbose) {
- DxConsole.out.println("processing archive " + file + "...");
+ DxConsole.out.println("processing archive " + file +
+ "...");
}
}
});
@@ -248,8 +250,8 @@
/**
* Processes one file, which may be either a class or a resource.
*
- * @param name non-null; name of the file
- * @param bytes non-null; contents of the file
+ * @param name {@code non-null;} name of the file
+ * @param bytes {@code non-null;} contents of the file
* @return whether processing was successful
*/
private static boolean processFileBytes(String name, byte[] bytes) {
@@ -283,9 +285,9 @@
/**
* Processes one classfile.
*
- * @param name non-null; name of the file, clipped such that it
+ * @param name {@code non-null;} name of the file, clipped such that it
* <i>should</i> correspond to the name of the class it contains
- * @param bytes non-null; contents of the file
+ * @param bytes {@code non-null;} contents of the file
* @return whether processing was successful
*/
private static boolean processClass(String name, byte[] bytes) {
@@ -316,7 +318,8 @@
* class. If there is a problem, this updates the error count and
* throws an exception to stop processing.
*
- * @param name non-null; the fully-qualified internal-form class name
+ * @param name {@code non-null;} the fully-qualified internal-form
+ * class name
*/
private static void checkClassName(String name) {
boolean bogus = false;
@@ -346,35 +349,60 @@
DxConsole.err.println("\ntrouble processing \"" + name + "\":");
DxConsole.err.println("\n" +
- "Attempt to include a core VM class in something other " +
- "than a core library.\n" +
- "It is likely that you have attempted to include the " +
- "core library from a desktop\n" +
- "virtual machine into an application, which will most " +
- "assuredly not work. If\n" +
- "you really intend to build a core library -- which is "+
- "only appropriate as\n" +
- "part of creating a full virtual machine binary, as " +
- "opposed to compiling an\n" +
- "application -- then use the \"--core-library\" option " +
- "to suppress this error\n" +
- "message. If you go ahead and use \"--core-library\" " +
- "but are in fact building\n" +
- "an application, then please be aware that your build " +
- "will still fail at some\n" +
- "point; you will simply be denied the pleasure of " +
- "reading this helpful error\n" +
- "message.");
+ "Attempt to include a core class (java.* or javax.*) in " +
+ "something other\n" +
+ "than a core library. It is likely that you have " +
+ "attempted to include\n" +
+ "in an application the core library (or a part thereof) " +
+ "from a desktop\n" +
+ "virtual machine. This will most assuredly not work. " +
+ "At a minimum, it\n" +
+ "jeopardizes the compatibility of your app with future " +
+ "versions of the\n" +
+ "platform. It is also often of questionable legality.\n" +
+ "\n" +
+ "If you really intend to build a core library -- which is " +
+ "only\n" +
+ "appropriate as part of creating a full virtual machine " +
+ "distribution,\n" +
+ "as opposed to compiling an application -- then use the\n" +
+ "\"--core-library\" option to suppress this error message.\n" +
+ "\n" +
+ "If you go ahead and use \"--core-library\" but are in " +
+ "fact building an\n" +
+ "application, then be forewarned that your application " +
+ "will still fail\n" +
+ "to build or run, at some point. Please be prepared for " +
+ "angry customers\n" +
+ "who find, for example, that your application ceases to " +
+ "function once\n" +
+ "they upgrade their operating system. You will be to " +
+ "blame for this\n" +
+ "problem.\n" +
+ "\n" +
+ "If you are legitimately using some code that happens to " +
+ "be in a core\n" +
+ "package, then the easiest safe alternative you have is " +
+ "to repackage\n" +
+ "that code. That is, move the classes in question into " +
+ "your own package\n" +
+ "namespace. This means that they will never be in " +
+ "conflict with core\n" +
+ "system classes. If you find that you cannot do this, " +
+ "then that is an\n" +
+ "indication that the path you are on will ultimately lead " +
+ "to pain,\n" +
+ "suffering, grief, and lamentation.\n");
errors++;
throw new StopProcessing();
}
/**
- * Converts {@link #outputDex} into a <code>byte[]</code>, write
+ * Converts {@link #outputDex} into a {@code byte[]}, write
* it out to the proper file (if any), and also do whatever human-oriented
* dumping is required.
*
- * @return null-ok; the converted <code>byte[]</code> or <code>null</code>
+ * @return {@code null-ok;} the converted {@code byte[]} or {@code null}
* if there was a problem
*/
private static byte[] writeDex() {
@@ -438,8 +466,9 @@
/**
* Creates a jar file from the resources and given dex file array.
*
- * @param fileName non-null; name of the file
- * @param dexArray non-null; array containing the dex file to include
+ * @param fileName {@code non-null;} name of the file
+ * @param dexArray {@code non-null;} array containing the dex file
+ * to include
* @return whether the creation was successful
*/
private static boolean createJar(String fileName, byte[] dexArray) {
@@ -496,7 +525,7 @@
* Creates and returns the manifest to use for the output. This may
* modify {@link #outputResources} (removing the pre-existing manifest).
*
- * @return non-null; the manifest
+ * @return {@code non-null;} the manifest
*/
private static Manifest makeManifest() throws IOException {
byte[] manifestBytes = outputResources.get(MANIFEST_NAME);
@@ -531,8 +560,8 @@
/**
* Opens and returns the named file for writing, treating "-" specially.
*
- * @param name non-null; the file name
- * @return non-null; the opened file
+ * @param name {@code non-null;} the file name
+ * @return {@code non-null;} the opened file
*/
private static OutputStream openOutput(String name) throws IOException {
if (name.equals("-") ||
@@ -547,9 +576,9 @@
* Flushes and closes the given output stream, except if it happens to be
* {@link System#out} in which case this method does the flush but not
* the close. This method will also silently do nothing if given a
- * <code>null</code> argument.
+ * {@code null} argument.
*
- * @param stream null-ok; what to close
+ * @param stream {@code null-ok;} what to close
*/
private static void closeOutput(OutputStream stream) throws IOException {
if (stream == null) {
@@ -565,18 +594,18 @@
/**
* Returns the "fixed" version of a given file path, suitable for
- * use as a path within a <code>.jar</code> file and for checking
+ * use as a path within a {@code .jar} file and for checking
* against a classfile-internal "this class" name. This looks for
- * the last instance of the substring <code>"/./"</code> within
+ * the last instance of the substring {@code "/./"} within
* the path, and if it finds it, it takes the portion after to be
* the fixed path. If that isn't found but the path starts with
- * <code>"./"</code>, then that prefix is removed and the rest is
+ * {@code "./"}, then that prefix is removed and the rest is
* return. If neither of these is the case, this method returns
* its argument.
*
- * @param path non-null; the path to "fix"
- * @return non-null; the fixed version (which might be the same as
- * the given <code>path</code>)
+ * @param path {@code non-null;} the path to "fix"
+ * @return {@code non-null;} the fixed version (which might be the same as
+ * the given {@code path})
*/
private static String fixPath(String path) {
/*
@@ -603,9 +632,10 @@
/**
* Dumps any method with the given name in the given file.
*
- * @param dex non-null; the dex file
- * @param fqName non-null; the fully-qualified name of the method(s)
- * @param out non-null; where to dump to
+ * @param dex {@code non-null;} the dex file
+ * @param fqName {@code non-null;} the fully-qualified name of the
+ * method(s)
+ * @param out {@code non-null;} where to dump to
*/
private static void dumpMethod(DexFile dex, String fqName,
OutputStreamWriter out) {
@@ -719,36 +749,36 @@
/** whether we are constructing a core library */
public boolean coreLibrary = false;
- /** null-ok; particular method to dump */
+ /** {@code null-ok;} particular method to dump */
public String methodToDump = null;
/** max width for columnar output */
public int dumpWidth = 0;
- /** null-ok; output file name for binary file */
+ /** {@code null-ok;} output file name for binary file */
public String outName = null;
- /** null-ok; output file name for human-oriented dump */
+ /** {@code null-ok;} output file name for human-oriented dump */
public String humanOutName = null;
/** whether strict file-name-vs-class-name checking should be done */
public boolean strictNameCheck = true;
/**
- * whether it is okay for there to be no <code>.class</code> files
+ * whether it is okay for there to be no {@code .class} files
* to process
*/
public boolean emptyOk = false;
/**
- * whether the binary output is to be a <code>.jar</code> file
- * instead of a plain <code>.dex</code>
+ * whether the binary output is to be a {@code .jar} file
+ * instead of a plain {@code .dex}
*/
public boolean jarOutput = false;
/**
- * when writing a <code>.jar</code> file, whether to still
- * keep the <code>.class</code> files
+ * when writing a {@code .jar} file, whether to still
+ * keep the {@code .class} files
*/
public boolean keepClassesInJar = false;
@@ -758,7 +788,7 @@
/** whether to keep local variable information */
public boolean localInfo = true;
- /** non-null after {@link #parse}; file name arguments */
+ /** {@code non-null after {@link #parse};} file name arguments */
public String[] fileNames;
/** whether to do SSA/register optimization */
@@ -779,7 +809,7 @@
/**
* Parses the given command-line arguments.
*
- * @param args non-null; the arguments
+ * @param args {@code non-null;} the arguments
*/
public void parse(String[] args) {
int at = 0;
@@ -866,8 +896,6 @@
}
int fileCount = args.length - at;
- fileNames = new String[fileCount];
- System.arraycopy(args, at, fileNames, 0, fileCount);
if (fileCount == 0) {
if (!emptyOk) {
@@ -876,9 +904,13 @@
}
} else if (emptyOk) {
System.out.println("ignoring input files");
- at = args.length;
+ at = 0;
+ fileCount = 0;
}
+ fileNames = new String[fileCount];
+ System.arraycopy(args, at, fileNames, 0, fileCount);
+
if ((humanOutName == null) && (methodToDump != null)) {
humanOutName = "-";
}
diff --git a/dx/src/com/android/dx/command/dump/BaseDumper.java b/dx/src/com/android/dx/command/dump/BaseDumper.java
index f4a8dee..d2c1e13 100644
--- a/dx/src/com/android/dx/command/dump/BaseDumper.java
+++ b/dx/src/com/android/dx/command/dump/BaseDumper.java
@@ -34,21 +34,21 @@
*/
public abstract class BaseDumper
implements ParseObserver {
- /** non-null; array of data being dumped */
+ /** {@code non-null;} array of data being dumped */
private final byte[] bytes;
/** whether or not to include the raw bytes (in a column on the left) */
private final boolean rawBytes;
- /** non-null; where to dump to */
+ /** {@code non-null;} where to dump to */
private final PrintStream out;
/** width of the output in columns */
private final int width;
/**
- * non-null; the file path for the class, excluding any base directory
- * specification
+ * {@code non-null;} the file path for the class, excluding any base
+ * directory specification
*/
private final String filePath;
@@ -61,7 +61,7 @@
/** the current level of indentation */
private int indent;
- /** non-null; the current column separator string */
+ /** {@code non-null;} the current column separator string */
private String separator;
/** the offset of the next byte to dump */
@@ -73,10 +73,9 @@
/**
* Constructs an instance.
*
- * @param bytes non-null; bytes of the (alleged) class file
+ * @param bytes {@code non-null;} bytes of the (alleged) class file
* on the left)
- * @param out non-null; where to dump to
- * passed in as <= 0
+ * @param out {@code non-null;} where to dump to
* @param filePath the file path for the class, excluding any base
* directory specification
*/
@@ -109,7 +108,8 @@
* @return width in register-units
*/
static int computeParamWidth(ConcreteMethod meth, boolean isStatic) {
- return meth.getEffectiveDescriptor().getParameterTypes().getWordCount();
+ return meth.getEffectiveDescriptor().getParameterTypes().
+ getWordCount();
}
/** {@inheritDoc} */
@@ -158,7 +158,7 @@
* Gets the current dump cursor (that is, the offset of the expected
* next byte to dump).
*
- * @return >= 0; the dump cursor
+ * @return {@code >= 0;} the dump cursor
*/
protected final int getAt() {
return at;
@@ -167,17 +167,17 @@
/**
* Sets the dump cursor to the indicated offset in the given array.
*
- * @param arr non-null; array in question
- * @param offset >= 0; offset into the array
+ * @param arr {@code non-null;} array in question
+ * @param offset {@code >= 0;} offset into the array
*/
protected final void setAt(ByteArray arr, int offset) {
at = arr.underlyingOffset(offset, bytes);
}
/**
- * Gets the array of <code>byte</code>s to process.
+ * Gets the array of {@code byte}s to process.
*
- * @return non-null; the bytes
+ * @return {@code non-null;} the bytes
*/
protected final byte[] getBytes() {
return bytes;
@@ -186,7 +186,7 @@
/**
* Gets the filesystem/jar path of the file being dumped.
*
- * @return non-null; the path
+ * @return {@code non-null;} the path
*/
protected final String getFilePath() {
return filePath;
@@ -204,7 +204,7 @@
/**
* Prints the given string to this instance's output stream.
*
- * @param s null-ok; string to print
+ * @param s {@code null-ok;} string to print
*/
protected final void print(String s) {
out.print(s);
@@ -214,7 +214,7 @@
* Prints the given string to this instance's output stream, followed
* by a newline.
*
- * @param s null-ok; string to print
+ * @param s {@code null-ok;} string to print
*/
protected final void println(String s) {
out.println(s);
@@ -230,10 +230,10 @@
}
/**
- * Gets the width of the first column of output. This is <code>0</code>
+ * Gets the width of the first column of output. This is {@code 0}
* unless raw bytes are being included in the output.
*
- * @return >= 0; the width of the first column
+ * @return {@code >= 0;} the width of the first column
*/
protected final int getWidth1() {
if (rawBytes) {
@@ -246,7 +246,7 @@
/**
* Gets the width of the second column of output.
*
- * @return >= 0; the width of the second column
+ * @return {@code >= 0;} the width of the second column
*/
protected final int getWidth2() {
int w1 = rawBytes ? (getWidth1() + 1) : 0;
@@ -258,7 +258,7 @@
*
* @param offset offset to start dumping at
* @param len length to dump
- * @return non-null; the dump
+ * @return {@code non-null;} the dump
*/
protected final String hexDump(int offset, int len) {
return Hex.dump(bytes, offset, len, offset, hexCols, 4);
@@ -268,9 +268,9 @@
* Combines a pair of strings as two columns, or if this is one-column
* output, format the otherwise-second column.
*
- * @param s1 non-null; the first column's string
- * @param s2 non-null; the second column's string
- * @return non-null; the combined output
+ * @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
*/
protected final String twoColumns(String s1, String s2) {
int w1 = getWidth1();
diff --git a/dx/src/com/android/dx/command/dump/BlockDumper.java b/dx/src/com/android/dx/command/dump/BlockDumper.java
index 0be2fb4..0858eab 100644
--- a/dx/src/com/android/dx/command/dump/BlockDumper.java
+++ b/dx/src/com/android/dx/command/dump/BlockDumper.java
@@ -54,14 +54,11 @@
private boolean rop;
/**
- * null-ok; the class file object being constructed; becomes non-null
- * during {@link #dump}
+ * {@code null-ok;} the class file object being constructed;
+ * becomes non-null during {@link #dump}
*/
protected DirectClassFile classFile;
- /** null-ok; most recently parsed code attribute */
- private AttCode codeAtt;
-
/** whether or not to suppress dumping */
protected boolean suppressDump;
@@ -75,9 +72,8 @@
* Dumps the given array, interpreting it as a class file and dumping
* methods with indications of block-level stuff.
*
- * @param bytes non-null; bytes of the (alleged) class file
- * @param out non-null; where to dump to
- * passed in as <= 0
+ * @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
* directory specification
* @param rop whether or not to registerize (make rop blocks)
@@ -102,7 +98,6 @@
this.rop = rop;
this.classFile = null;
- this.codeAtt = null;
this.suppressDump = true;
this.first = true;
this.optimize = args.optimize;
@@ -208,7 +203,7 @@
/**
* Does a regular basic block dump.
*
- * @param meth non-null; method data to dump
+ * @param meth {@code non-null;} method data to dump
*/
private void regularDump(ConcreteMethod meth) {
BytecodeArray code = meth.getCode();
@@ -283,7 +278,7 @@
/**
* Does a registerizing dump.
*
- * @param meth non-null; method data to dump
+ * @param meth {@code non-null;} method data to dump
*/
private void ropDump(ConcreteMethod meth) {
BytecodeArray code = meth.getCode();
diff --git a/dx/src/com/android/dx/command/dump/ClassDumper.java b/dx/src/com/android/dx/command/dump/ClassDumper.java
index 10dacf3..e98b6d6 100644
--- a/dx/src/com/android/dx/command/dump/ClassDumper.java
+++ b/dx/src/com/android/dx/command/dump/ClassDumper.java
@@ -30,8 +30,8 @@
/**
* Dumps the given array, interpreting it as a class file.
*
- * @param bytes non-null; bytes of the (alleged) class file
- * @param out non-null; where to dump to
+ * @param bytes {@code non-null;} bytes of the (alleged) class file
+ * @param out {@code non-null;} where to dump to
* passed in as <= 0
* @param filePath the file path for the class, excluding any base
* directory specification
diff --git a/dx/src/com/android/dx/command/dump/DotDumper.java b/dx/src/com/android/dx/command/dump/DotDumper.java
index 87c5298..9de48fc 100644
--- a/dx/src/com/android/dx/command/dump/DotDumper.java
+++ b/dx/src/com/android/dx/command/dump/DotDumper.java
@@ -39,16 +39,15 @@
* with the popular graph utility "dot".
*/
public class DotDumper implements ParseObserver {
+ private DirectClassFile classFile;
- DirectClassFile classFile;
+ private final byte[] bytes;
+ private final String filePath;
+ private final boolean strictParse;
+ private final boolean optimize;
+ private final Args args;
- byte[] bytes;
- String filePath;
- boolean strictParse;
- boolean optimize;
- Args args;
-
- static void dump (byte[] bytes, String filePath, Args args) {
+ static void dump(byte[] bytes, String filePath, Args args) {
new DotDumper(bytes, filePath, args).run();
}
@@ -60,7 +59,6 @@
this.args = args;
}
-
private void run() {
ByteArray ba = new ByteArray(bytes);
@@ -89,17 +87,17 @@
}
public void changeIndent(int indentDelta) {
-
+ // This space intentionally left blank.
}
public void parsed(ByteArray bytes, int offset, int len, String human) {
-
+ // This space intentionally left blank.
}
/** {@inheritDoc} */
public void startParsingMember(ByteArray bytes, int offset, String name,
String descriptor) {
-
+ // This space intentionally left blank.
}
public void endParsingMember(ByteArray bytes, int offset, String name,
@@ -165,6 +163,5 @@
}
System.out.println("}");
-
}
}
diff --git a/dx/src/com/android/dx/command/dump/Main.java b/dx/src/com/android/dx/command/dump/Main.java
index 1ea26bc..d6ba374 100644
--- a/dx/src/com/android/dx/command/dump/Main.java
+++ b/dx/src/com/android/dx/command/dump/Main.java
@@ -110,8 +110,8 @@
/**
* Processes one file.
*
- * @param name non-null; name of the file
- * @param bytes non-null; contents of the file
+ * @param name {@code non-null;} name of the file
+ * @param bytes {@code non-null;} contents of the file
*/
private static void processOne(String name, byte[] bytes) {
if (parsedArgs.dotDump) {
diff --git a/dx/src/com/android/dx/command/dump/SsaDumper.java b/dx/src/com/android/dx/command/dump/SsaDumper.java
index 95442a1..e5e9d97 100644
--- a/dx/src/com/android/dx/command/dump/SsaDumper.java
+++ b/dx/src/com/android/dx/command/dump/SsaDumper.java
@@ -40,29 +40,48 @@
import com.android.dx.util.IntList;
import java.io.PrintStream;
+import java.util.ArrayList;
import java.util.BitSet;
+import java.util.Collections;
import java.util.EnumSet;
+/**
+ * Dumper for the SSA-translated blocks of a method.
+ */
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
+ * directory specification
+ * @param args commandline parsedArgs
+ */
public static void dump(byte[] bytes, PrintStream out,
String filePath, Args args) {
-
- SsaDumper sd =
- new SsaDumper(bytes, out, filePath, args);
+ SsaDumper sd = new SsaDumper(bytes, out, filePath, args);
sd.dump();
}
- SsaDumper(byte[] bytes, PrintStream out, String filePath, Args args) {
-
+ /**
+ * 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
+ * directory specification
+ * @param args commandline parsedArgs
+ */
+ private SsaDumper(byte[] bytes, PrintStream out, String filePath,
+ Args args) {
super(bytes, out, filePath, true, args);
-
}
/** {@inheritDoc} */
@Override
public void endParsingMember(ByteArray bytes, int offset, String name,
- String descriptor, Member member) {
+ String descriptor, Member member) {
if (!(member instanceof Method)) {
return;
}
@@ -71,17 +90,14 @@
return;
}
- ConcreteMethod meth = new ConcreteMethod((Method) member, classFile,
- true, true);
-
+ ConcreteMethod meth =
+ new ConcreteMethod((Method) member, classFile, true, true);
TranslationAdvice advice = DexTranslationAdvice.THE_ONE;
-
RopMethod rmeth = Ropper.convert(meth, advice);
-
SsaMethod ssaMeth = null;
-
boolean isStatic = AccessFlags.isStatic(meth.getAccessFlags());
int paramWidth = computeParamWidth(meth, isStatic);
+
if (args.ssaStep == null) {
ssaMeth = Optimizer.debugNoRegisterAllocation(rmeth,
paramWidth, isStatic, true, advice,
@@ -106,30 +122,36 @@
sb.append(Hex.u2(
ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex())));
sb.append('\n');
+
+ ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
+ ArrayList<SsaBasicBlock> sortedBlocks =
+ (ArrayList<SsaBasicBlock>) blocks.clone();
+ Collections.sort(sortedBlocks, SsaBasicBlock.LABEL_COMPARATOR);
- for (SsaBasicBlock block : ssaMeth.getBlocks()) {
+ for (SsaBasicBlock block : sortedBlocks) {
sb.append("block ")
.append(Hex.u2(block.getRopLabel())).append('\n');
BitSet preds = block.getPredecessors();
- for(int i=preds.nextSetBit(0); i>=0; i=preds.nextSetBit(i+1)) {
- sb.append (" pred ");
- sb.append (Hex.u2(ssaMeth.blockIndexToRopLabel(i)));
+ for (int i = preds.nextSetBit(0); i >= 0;
+ i = preds.nextSetBit(i+1)) {
+ sb.append(" pred ");
+ sb.append(Hex.u2(ssaMeth.blockIndexToRopLabel(i)));
sb.append('\n');
}
- sb.append (" live in:" + block.getLiveInRegs());
- sb.append ("\n");
+ sb.append(" live in:" + block.getLiveInRegs());
+ sb.append("\n");
- for (SsaInsn insn: block.getInsns()) {
+ for (SsaInsn insn : block.getInsns()) {
sb.append(" ");
sb.append(insn.toHuman());
sb.append('\n');
}
if (block.getSuccessors().cardinality() == 0) {
- sb.append (" returns\n");
+ sb.append(" returns\n");
} else {
int primary = block.getPrimarySuccessorRopLabel();
@@ -138,18 +160,18 @@
int szSuccLabels = succLabelList.size();
for (int i = 0; i < szSuccLabels; i++) {
- sb.append (" next ");
- sb.append (Hex.u2(succLabelList.get(i)));
+ sb.append(" next ");
+ sb.append(Hex.u2(succLabelList.get(i)));
if (szSuccLabels != 1 && primary == succLabelList.get(i)) {
- sb.append (" *");
+ sb.append(" *");
}
sb.append('\n');
}
}
- sb.append (" live out:" + block.getLiveOutRegs());
- sb.append ("\n");
+ sb.append(" live out:" + block.getLiveOutRegs());
+ sb.append("\n");
}
suppressDump = false;
diff --git a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
index dab15c9..cdd29d7 100644
--- a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
+++ b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
@@ -51,7 +51,7 @@
/**
* Utility methods that translate various classfile attributes
- * into forms suitable for use in creating <code>dex</code> files.
+ * into forms suitable for use in creating {@code dex} files.
*/
/*package*/ class AttributeTranslator {
/**
@@ -64,8 +64,8 @@
/**
* Gets the list of thrown exceptions for a given method.
*
- * @param method non-null; the method in question
- * @return non-null; the list of thrown exceptions
+ * @param method {@code non-null;} the method in question
+ * @return {@code non-null;} the list of thrown exceptions
*/
public static TypeList getExceptions(Method method) {
AttributeList attribs = method.getAttributes();
@@ -83,10 +83,10 @@
* Gets the annotations out of a given {@link AttributeList}. This
* combines both visible and invisible annotations into a single
* result set and also adds in a system annotation for the
- * <code>Signature</code> attribute if present.
+ * {@code Signature} attribute if present.
*
- * @param attribs non-null; the attributes list to search in
- * @return non-null; the set of annotations, which may be empty
+ * @param attribs {@code non-null;} the attributes list to search in
+ * @return {@code non-null;} the set of annotations, which may be empty
*/
public static Annotations getAnnotations(AttributeList attribs) {
Annotations result = getAnnotations0(attribs);
@@ -102,15 +102,15 @@
/**
* Gets the annotations out of a given class, similar to {@link
* #getAnnotations}, also including annotations for translations
- * of class-level attributes <code>EnclosingMethod</code> and
- * <code>InnerClasses</code>, if present. Additionally, if the
+ * of class-level attributes {@code EnclosingMethod} and
+ * {@code InnerClasses}, if present. Additionally, if the
* class is an annotation class, then this also includes a
- * representation of all the <code>AnnotationDefault</code>
+ * representation of all the {@code AnnotationDefault}
* values.
*
- * @param cf non-null; the class in question
- * @param args non-null; the high-level options
- * @return non-null; the set of annotations, which may be empty
+ * @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
*/
public static Annotations getClassAnnotations(DirectClassFile cf,
CfOptions args) {
@@ -148,10 +148,10 @@
/**
* 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</code>.
+ * of the method-specific attribute {@code Exceptions}.
*
- * @param method non-null; the method in question
- * @return non-null; the set of annotations, which may be empty
+ * @param method {@code non-null;} the method in question
+ * @return {@code non-null;} the set of annotations, which may be empty
*/
public static Annotations getMethodAnnotations(Method method) {
Annotations result = getAnnotations(method.getAttributes());
@@ -170,8 +170,8 @@
* Helper method for {@link #getAnnotations} which just gets the
* existing annotations, per se.
*
- * @param attribs non-null; the attributes list to search in
- * @return non-null; the set of annotations, which may be empty
+ * @param attribs {@code non-null;} the attributes list to search in
+ * @return {@code non-null;} the set of annotations, which may be empty
*/
private static Annotations getAnnotations0(AttributeList attribs) {
AttRuntimeVisibleAnnotations visible =
@@ -199,11 +199,11 @@
}
/**
- * Gets the <code>Signature</code> attribute out of a given
+ * Gets the {@code Signature} attribute out of a given
* {@link AttributeList}, if any, translating it to an annotation.
*
- * @param attribs non-null; the attributes list to search in
- * @return null-ok; the converted <code>Signature</code> 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
*/
private static Annotation getSignature(AttributeList attribs) {
@@ -218,15 +218,15 @@
}
/**
- * Gets the <code>EnclosingMethod</code> attribute out of a given
+ * Gets the {@code EnclosingMethod} attribute out of a given
* {@link AttributeList}, if any, translating it to an annotation.
* If the class really has an enclosing method, this returns an
- * <code>EnclosingMethod</code> annotation; if not, this returns
- * an <code>EnclosingClass</code> annotation.
+ * {@code EnclosingMethod} annotation; if not, this returns
+ * an {@code EnclosingClass} annotation.
*
- * @param attribs non-null; the attributes list to search in
- * @return null-ok; the converted <code>EnclosingMethod</code> or
- * <code>EnclosingClass</code> annotation, if there was an
+ * @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
* attribute to translate
*/
private static Annotation translateEnclosingMethod(AttributeList attribs) {
@@ -256,16 +256,16 @@
}
/**
- * Gets the <code>InnerClasses</code> attribute out of a given
+ * Gets the {@code InnerClasses} attribute out of a given
* {@link AttributeList}, if any, translating it to one or more of an
- * <code>InnerClass</code>, <code>EnclosingClass</code>, or
- * <code>MemberClasses</code> annotation.
+ * {@code InnerClass}, {@code EnclosingClass}, or
+ * {@code MemberClasses} annotation.
*
- * @param thisClass non-null; type representing the class being processed
- * @param attribs non-null; the attributes list to search in
+ * @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</code> annotation
- * @return null-ok; the converted list of annotations, if there
+ * {@code EnclosingClass} annotation
+ * @return {@code null-ok;} the converted list of annotations, if there
* was an attribute to translate
*/
private static Annotations translateInnerClasses(CstType thisClass,
@@ -342,8 +342,8 @@
* combines both visible and invisible annotations into a single
* result set.
*
- * @param method non-null; the method in question
- * @return non-null; the list of annotation sets, which may be empty
+ * @param method {@code non-null;} the method in question
+ * @return {@code non-null;} the list of annotation sets, which may be empty
*/
public static AnnotationsList getParameterAnnotations(Method method) {
AttributeList attribs = method.getAttributes();
@@ -374,14 +374,14 @@
}
/**
- * Gets the <code>AnnotationDefault</code> attributes out of a
+ * Gets the {@code AnnotationDefault} attributes out of a
* given class, if any, reforming them as an
- * <code>AnnotationDefault</code> annotation.
+ * {@code AnnotationDefault} annotation.
*
- * @param cf non-null; the class in question
- * @return null-ok; an appropriately-constructed
- * <code>AnnotationDefault</code> annotation, if there were any
- * annotation defaults in the class, or <code>null<code> if not
+ * @param cf {@code non-null;} the class in question
+ * @return {@code null-ok;} an appropriately-constructed
+ * {@code AnnotationDefault} annotation, if there were any
+ * annotation defaults in the class, or {@code null} if not
*/
private static Annotation translateAnnotationDefaults(DirectClassFile cf) {
CstType thisClass = cf.getThisClass();
diff --git a/dx/src/com/android/dx/dex/cf/CfTranslator.java b/dx/src/com/android/dx/dex/cf/CfTranslator.java
index c48be53..8210e90 100644
--- a/dx/src/com/android/dx/dex/cf/CfTranslator.java
+++ b/dx/src/com/android/dx/dex/cf/CfTranslator.java
@@ -55,11 +55,11 @@
import com.android.dx.util.ExceptionWithContext;
/**
- * Static method that turns <code>byte[]</code>s containing Java
+ * Static method that turns {@code byte[]}s containing Java
* classfiles into {@link ClassDefItem} instances.
*/
public class CfTranslator {
- /** set to <code>true</code> to enable development-time debugging code */
+ /** set to {@code true} to enable development-time debugging code */
private static final boolean DEBUG = false;
/**
@@ -70,14 +70,14 @@
}
/**
- * Takes a <code>byte[]</code>, interprets it as a Java classfile, and
+ * Takes a {@code byte[]}, interprets it as a Java classfile, and
* translates it into a {@link ClassDefItem}.
*
- * @param filePath non-null; the file path for the class,
+ * @param filePath {@code non-null;} the file path for the class,
* excluding any base directory specification
- * @param bytes non-null; contents of the file
+ * @param bytes {@code non-null;} contents of the file
* @param args command-line arguments
- * @return non-null; the translated class
+ * @return {@code non-null;} the translated class
*/
public static ClassDefItem translate(String filePath, byte[] bytes,
CfOptions args) {
@@ -94,11 +94,11 @@
* from {@link #translate} just to keep things a bit simpler in
* terms of exception handling.
*
- * @param filePath non-null; the file path for the class,
+ * @param filePath {@code non-null;} the file path for the class,
* excluding any base directory specification
- * @param bytes non-null; contents of the file
+ * @param bytes {@code non-null;} contents of the file
* @param args command-line arguments
- * @return non-null; the translated class
+ * @return {@code non-null;} the translated class
*/
private static ClassDefItem translate0(String filePath, byte[] bytes,
CfOptions args) {
@@ -136,8 +136,8 @@
/**
* Processes the fields of the given class.
*
- * @param cf non-null; class being translated
- * @param out non-null; output class
+ * @param cf {@code non-null;} class being translated
+ * @param out {@code non-null;} output class
*/
private static void processFields(DirectClassFile cf, ClassDefItem out) {
CstType thisClass = cf.getThisClass();
@@ -179,8 +179,8 @@
* Helper for {@link #processFields}, which translates constants into
* more specific types if necessary.
*
- * @param constant non-null; the constant in question
- * @param type non-null; the desired type
+ * @param constant {@code non-null;} the constant in question
+ * @param type {@code non-null;} the desired type
*/
private static TypedConstant coerceConstant(TypedConstant constant,
Type type) {
@@ -213,9 +213,9 @@
/**
* Processes the methods of the given class.
*
- * @param cf non-null; class being translated
- * @param args non-null; command-line args
- * @param out non-null; output class
+ * @param cf {@code non-null;} class being translated
+ * @param args {@code non-null;} command-line args
+ * @param out {@code non-null;} output class
*/
private static void processMethods(DirectClassFile cf,
CfOptions args, ClassDefItem out) {
diff --git a/dx/src/com/android/dx/dex/cf/CodeStatistics.java b/dx/src/com/android/dx/dex/cf/CodeStatistics.java
index fa83100..b692d77 100644
--- a/dx/src/com/android/dx/dex/cf/CodeStatistics.java
+++ b/dx/src/com/android/dx/dex/cf/CodeStatistics.java
@@ -26,7 +26,7 @@
* code.
*/
public final class CodeStatistics {
- /** set to <code>true</code> to enable development-time debugging code */
+ /** set to {@code true} to enable development-time debugging code */
private static final boolean DEBUG = false;
/**
@@ -76,7 +76,7 @@
/**
* Updates the number of original bytecode bytes processed.
*
- * @param count >= 0; the number of bytes to add
+ * @param count {@code >= 0;} the number of bytes to add
*/
public static void updateOriginalByteCount(int count) {
runningOriginalBytes += count;
@@ -146,7 +146,7 @@
/**
* Prints out the collected statistics.
*
- * @param out non-null; where to output to
+ * @param out {@code non-null;} where to output to
*/
public static void dumpStatistics(PrintStream out) {
out.printf("Optimizer Delta Rop Insns: %d total: %d "
diff --git a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
index 1dc3f76..fa606e3 100644
--- a/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
+++ b/dx/src/com/android/dx/dex/cf/OptimizerOptions.java
@@ -31,13 +31,14 @@
*/
public class OptimizerOptions {
/**
- * null-ok; hash set of class name + method names that should be optimized.
- * null if this constraint was not specified on the command line
+ * {@code null-ok;} hash set of class name + method names that
+ * should be optimized. {@code null} if this constraint was not
+ * specified on the command line
*/
private static HashSet<String> optimizeList;
/**
- * null-ok; hash set of class name + method names that should NOT
+ * {@code null-ok;} hash set of class name + method names that should NOT
* be optimized. null if this constraint was not specified on the
* command line
*/
@@ -97,7 +98,6 @@
try {
FileReader fr = new FileReader(filename);
-
BufferedReader bfr = new BufferedReader(fr);
String line;
@@ -105,6 +105,8 @@
while (null != (line = bfr.readLine())) {
result.add(line);
}
+
+ fr.close();
} catch (IOException ex) {
// Let the exception percolate up as a RuntimeException.
throw new RuntimeException("Error with optimize list: " +
@@ -118,12 +120,12 @@
* Compares the output of the optimizer run normally with a run skipping
* some optional steps. Results are printed to stderr.
*
- * @param nonOptRmeth non-null; origional rop method
- * @param paramSize >= 0 parameter size of method
+ * @param nonOptRmeth {@code non-null;} origional rop method
+ * @param paramSize {@code >= 0;} parameter size of method
* @param isStatic true if this method has no 'this' pointer argument.
- * @param args non-null; translator arguments
- * @param advice non-null; translation advice
- * @param rmeth non-null; method with all optimization steps run.
+ * @param args {@code non-null;} translator arguments
+ * @param advice {@code non-null;} translation advice
+ * @param rmeth {@code non-null;} method with all optimization steps run.
*/
public static void compareOptimizerStep(RopMethod nonOptRmeth,
int paramSize, boolean isStatic, CfOptions args,
diff --git a/dx/src/com/android/dx/dex/code/ArrayData.java b/dx/src/com/android/dx/dex/code/ArrayData.java
index 8476a03..7698de1 100644
--- a/dx/src/com/android/dx/dex/code/ArrayData.java
+++ b/dx/src/com/android/dx/dex/code/ArrayData.java
@@ -29,12 +29,12 @@
*/
public final class ArrayData extends VariableSizeInsn {
/**
- * non-null; address representing the instruction that uses this
+ * {@code non-null;} address representing the instruction that uses this
* instance
*/
private final CodeAddress user;
- /** non-null; initial values to be filled into an array */
+ /** {@code non-null;} initial values to be filled into an array */
private final ArrayList<Constant> values;
/** non-null: type of constant that initializes the array */
@@ -48,12 +48,12 @@
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param user non-null; address representing the instruction that
+ * @param position {@code non-null;} source position
+ * @param user {@code non-null;} address representing the instruction that
* uses this instance
- * @param values non-null; initial values to be filled into an array
+ * @param values {@code non-null;} initial values to be filled into an array
*/
public ArrayData(SourcePosition position, CodeAddress user,
ArrayList<Constant> values,
@@ -107,7 +107,6 @@
/** {@inheritDoc} */
@Override
public void writeTo(AnnotatedOutput out) {
- int baseAddress = user.getAddress();
int sz = values.size();
out.writeShort(0x300 | DalvOps.NOP);
diff --git a/dx/src/com/android/dx/dex/code/BlockAddresses.java b/dx/src/com/android/dx/dex/code/BlockAddresses.java
index 9fea66c..e55f893 100644
--- a/dx/src/com/android/dx/dex/code/BlockAddresses.java
+++ b/dx/src/com/android/dx/dex/code/BlockAddresses.java
@@ -28,15 +28,15 @@
* start address, end address, and last instruction address.
*/
public final class BlockAddresses {
- /** non-null; array containing addresses for the start of each basic
+ /** {@code non-null;} array containing addresses for the start of each basic
* block (indexed by basic block label) */
private final CodeAddress[] starts;
- /** non-null; array containing addresses for the final instruction
+ /** {@code non-null;} array containing addresses for the final instruction
* of each basic block (indexed by basic block label) */
private final CodeAddress[] lasts;
- /** non-null; array containing addresses for the end (just past the
+ /** {@code non-null;} array containing addresses for the end (just past the
* final instruction) of each basic block (indexed by basic block
* label) */
private final CodeAddress[] ends;
@@ -44,7 +44,7 @@
/**
* Constructs an instance.
*
- * @param method non-null; the method to have block addresses for
+ * @param method {@code non-null;} the method to have block addresses for
*/
public BlockAddresses(RopMethod method) {
BasicBlockList blocks = method.getBlocks();
@@ -60,8 +60,8 @@
/**
* Gets the instance for the start of the given block.
*
- * @param block non-null; the block in question
- * @return non-null; the appropriate instance
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the appropriate instance
*/
public CodeAddress getStart(BasicBlock block) {
return starts[block.getLabel()];
@@ -70,8 +70,8 @@
/**
* Gets the instance for the start of the block with the given label.
*
- * @param label non-null; the label of the block in question
- * @return non-null; the appropriate instance
+ * @param label {@code non-null;} the label of the block in question
+ * @return {@code non-null;} the appropriate instance
*/
public CodeAddress getStart(int label) {
return starts[label];
@@ -80,8 +80,8 @@
/**
* Gets the instance for the final instruction of the given block.
*
- * @param block non-null; the block in question
- * @return non-null; the appropriate instance
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the appropriate instance
*/
public CodeAddress getLast(BasicBlock block) {
return lasts[block.getLabel()];
@@ -91,8 +91,8 @@
* Gets the instance for the final instruction of the block with
* the given label.
*
- * @param label non-null; the label of the block in question
- * @return non-null; the appropriate instance
+ * @param label {@code non-null;} the label of the block in question
+ * @return {@code non-null;} the appropriate instance
*/
public CodeAddress getLast(int label) {
return lasts[label];
@@ -102,8 +102,8 @@
* Gets the instance for the end (address after the final instruction)
* of the given block.
*
- * @param block non-null; the block in question
- * @return non-null; the appropriate instance
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the appropriate instance
*/
public CodeAddress getEnd(BasicBlock block) {
return ends[block.getLabel()];
@@ -113,8 +113,8 @@
* Gets the instance for the end (address after the final instruction)
* of the block with the given label.
*
- * @param label non-null; the label of the block in question
- * @return non-null; the appropriate instance
+ * @param label {@code non-null;} the label of the block in question
+ * @return {@code non-null;} the appropriate instance
*/
public CodeAddress getEnd(int label) {
return ends[label];
diff --git a/dx/src/com/android/dx/dex/code/CatchBuilder.java b/dx/src/com/android/dx/dex/code/CatchBuilder.java
index 8bc963b..d2ec3d7 100644
--- a/dx/src/com/android/dx/dex/code/CatchBuilder.java
+++ b/dx/src/com/android/dx/dex/code/CatchBuilder.java
@@ -27,7 +27,7 @@
/**
* Builds and returns the catch table for this instance.
*
- * @return non-null; the constructed table
+ * @return {@code non-null;} the constructed table
*/
public CatchTable build();
@@ -42,7 +42,7 @@
/**
* Gets the set of catch types associated with this instance.
*
- * @return non-null; the set of catch types
+ * @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 862586c..a8a97be 100644
--- a/dx/src/com/android/dx/dex/code/CatchHandlerList.java
+++ b/dx/src/com/android/dx/dex/code/CatchHandlerList.java
@@ -25,13 +25,13 @@
*/
public final class CatchHandlerList extends FixedSizeList
implements Comparable<CatchHandlerList> {
- /** non-null; empty instance */
+ /** {@code non-null;} empty instance */
public static final CatchHandlerList EMPTY = new CatchHandlerList(0);
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
- * @param size >= 0; the size of the list
+ * @param size {@code >= 0;} the size of the list
*/
public CatchHandlerList(int size) {
super(size);
@@ -40,10 +40,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Entry get(int n) {
return (Entry) get0(n);
@@ -58,10 +58,10 @@
* Get the human form of this instance, prefixed on each line
* with the string.
*
- * @param prefix non-null; the prefix for every line
- * @param header non-null; the header for the first line (after the
+ * @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)
- * @return non-null; the human form
+ * @return {@code non-null;} the human form
*/
public String toHuman(String prefix, String header) {
StringBuilder sb = new StringBuilder(100);
@@ -97,8 +97,8 @@
* Returns whether or not this instance ends with a "catch-all"
* handler.
*
- * @return <code>true</code> if this instance ends with a "catch-all"
- * handler or <code>false</code> if not
+ * @return {@code true} if this instance ends with a "catch-all"
+ * handler or {@code false} if not
*/
public boolean catchesAll() {
int size = size();
@@ -114,9 +114,9 @@
/**
* Sets the entry at the given index.
*
- * @param n >= 0, < size(); which index
- * @param exceptionType non-null; type of exception handled
- * @param handler >= 0; exception handler address
+ * @param n {@code >= 0, < size();} which index
+ * @param exceptionType {@code non-null;} type of exception handled
+ * @param handler {@code >= 0;} exception handler address
*/
public void set(int n, CstType exceptionType, int handler) {
set0(n, new Entry(exceptionType, handler));
@@ -125,8 +125,8 @@
/**
* Sets the entry at the given index.
*
- * @param n >= 0, < size(); which index
- * @param entry non-null; the entry to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
*/
public void set(int n, Entry entry) {
set0(n, entry);
@@ -165,17 +165,17 @@
* Entry in the list.
*/
public static class Entry implements Comparable<Entry> {
- /** non-null; type of exception handled */
+ /** {@code non-null;} type of exception handled */
private final CstType exceptionType;
- /** >= 0; exception handler address */
+ /** {@code >= 0;} exception handler address */
private final int handler;
/**
* Constructs an instance.
*
- * @param exceptionType non-null; type of exception handled
- * @param handler >= 0; exception handler address
+ * @param exceptionType {@code non-null;} type of exception handled
+ * @param handler {@code >= 0;} exception handler address
*/
public Entry(CstType exceptionType, int handler) {
if (handler < 0) {
@@ -220,7 +220,7 @@
/**
* Gets the exception type handled.
*
- * @return non-null; the exception type
+ * @return {@code non-null;} the exception type
*/
public CstType getExceptionType() {
return exceptionType;
@@ -229,7 +229,7 @@
/**
* Gets the handler address.
*
- * @return >= 0; the handler address
+ * @return {@code >= 0;} the handler address
*/
public int getHandler() {
return handler;
diff --git a/dx/src/com/android/dx/dex/code/CatchTable.java b/dx/src/com/android/dx/dex/code/CatchTable.java
index 86f9c58..fd8e3a7 100644
--- a/dx/src/com/android/dx/dex/code/CatchTable.java
+++ b/dx/src/com/android/dx/dex/code/CatchTable.java
@@ -26,13 +26,13 @@
*/
public final class CatchTable extends FixedSizeList
implements Comparable<CatchTable> {
- /** non-null; empty instance */
+ /** {@code non-null;} empty instance */
public static final CatchTable EMPTY = new CatchTable(0);
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
- * @param size >= 0; the size of the table
+ * @param size {@code >= 0;} the size of the table
*/
public CatchTable(int size) {
super(size);
@@ -41,10 +41,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Entry get(int n) {
return (Entry) get0(n);
@@ -53,8 +53,8 @@
/**
* Sets the entry at the given index.
*
- * @param n >= 0, < size(); which index
- * @param entry non-null; the entry to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
*/
public void set(int n, Entry entry) {
set0(n, entry);
@@ -93,21 +93,21 @@
* Entry in a catch list.
*/
public static class Entry implements Comparable<Entry> {
- /** >= 0; start address */
+ /** {@code >= 0;} start address */
private final int start;
- /** > start; end address (exclusive) */
+ /** {@code > start;} end address (exclusive) */
private final int end;
- /** non-null; list of catch handlers */
+ /** {@code non-null;} list of catch handlers */
private final CatchHandlerList handlers;
/**
* Constructs an instance.
*
- * @param start >= 0; start address
- * @param end > start; end address (exclusive)
- * @param handlers non-null; list of catch handlers
+ * @param start {@code >= 0;} start address
+ * @param end {@code > start;} end address (exclusive)
+ * @param handlers {@code non-null;} list of catch handlers
*/
public Entry(int start, int end, CatchHandlerList handlers) {
if (start < 0) {
@@ -165,7 +165,7 @@
/**
* Gets the start address.
*
- * @return >= 0; the start address
+ * @return {@code >= 0;} the start address
*/
public int getStart() {
return start;
@@ -174,7 +174,7 @@
/**
* Gets the end address (exclusive).
*
- * @return > start; the end address (exclusive)
+ * @return {@code > start;} the end address (exclusive)
*/
public int getEnd() {
return end;
@@ -183,7 +183,7 @@
/**
* Gets the handlers.
*
- * @return non-null; the handlers
+ * @return {@code non-null;} the handlers
*/
public CatchHandlerList getHandlers() {
return handlers;
diff --git a/dx/src/com/android/dx/dex/code/CodeAddress.java b/dx/src/com/android/dx/dex/code/CodeAddress.java
index 9730913..f25718e 100644
--- a/dx/src/com/android/dx/dex/code/CodeAddress.java
+++ b/dx/src/com/android/dx/dex/code/CodeAddress.java
@@ -29,9 +29,9 @@
public final class CodeAddress extends ZeroSizeInsn {
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
+ * @param position {@code non-null;} source position
*/
public CodeAddress(SourcePosition position) {
super(position);
diff --git a/dx/src/com/android/dx/dex/code/CstInsn.java b/dx/src/com/android/dx/dex/code/CstInsn.java
index 1bc9021..a579c5e 100644
--- a/dx/src/com/android/dx/dex/code/CstInsn.java
+++ b/dx/src/com/android/dx/dex/code/CstInsn.java
@@ -25,31 +25,31 @@
* to all the normal instruction information.
*/
public final class CstInsn extends FixedSizeInsn {
- /** non-null; the constant argument for this instruction */
+ /** {@code non-null;} the constant argument for this instruction */
private final Constant constant;
/**
- * >= -1; the constant pool index for {@link #constant}, or
- * <code>-1</code> if not yet set
+ * {@code >= -1;} the constant pool index for {@link #constant}, or
+ * {@code -1} if not yet set
*/
private int index;
/**
- * >= -1; the constant pool index for the class reference in
- * {@link #constant} if any, or <code>-1</code> if not yet set
+ * {@code >= -1;} the constant pool index for the class reference in
+ * {@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</code>) as is the constant pool index.
+ * initially unknown ({@code -1}) as is the constant pool index.
*
* @param opcode the opcode; one of the constants from {@link Dops}
- * @param position non-null; source position
- * @param registers non-null; register list, including a
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
* result register if appropriate (that is, registers may be either
* ins or outs)
- * @param constant non-null; constant argument
+ * @param constant {@code non-null;} constant argument
*/
public CstInsn(Dop opcode, SourcePosition position,
RegisterSpecList registers, Constant constant) {
@@ -101,7 +101,7 @@
/**
* Gets the constant argument.
*
- * @return non-null; the constant argument
+ * @return {@code non-null;} the constant argument
*/
public Constant getConstant() {
return constant;
@@ -111,7 +111,7 @@
* Gets the constant's index. It is only valid to call this after
* {@link #setIndex} has been called.
*
- * @return >= 0; the constant pool index
+ * @return {@code >= 0;} the constant pool index
*/
public int getIndex() {
if (index < 0) {
@@ -126,7 +126,7 @@
*
* @see #setIndex
*
- * @return <code>true</code> iff the index has been set
+ * @return {@code true} iff the index has been set
*/
public boolean hasIndex() {
return (index >= 0);
@@ -136,7 +136,7 @@
* Sets the constant's index. It is only valid to call this method once
* per instance.
*
- * @param index >= 0; the constant pool index
+ * @param index {@code >= 0;} the constant pool index
*/
public void setIndex(int index) {
if (index < 0) {
@@ -154,7 +154,7 @@
* Gets the constant's class index. It is only valid to call this after
* {@link #setClassIndex} has been called.
*
- * @return >= 0; the constant's class's constant pool index
+ * @return {@code >= 0;} the constant's class's constant pool index
*/
public int getClassIndex() {
if (classIndex < 0) {
@@ -170,7 +170,7 @@
*
* @see #setClassIndex
*
- * @return <code>true</code> iff the index has been set
+ * @return {@code true} iff the index has been set
*/
public boolean hasClassIndex() {
return (classIndex >= 0);
@@ -183,7 +183,7 @@
* with reference constants that this method should ever be
* called. It is only valid to call this method once per instance.
*
- * @param index >= 0; the constant's class's constant pool index
+ * @param index {@code >= 0;} the constant's class's constant pool index
*/
public void setClassIndex(int index) {
if (index < 0) {
diff --git a/dx/src/com/android/dx/dex/code/DalvCode.java b/dx/src/com/android/dx/dex/code/DalvCode.java
index cf6af09..f911912 100644
--- a/dx/src/com/android/dx/dex/code/DalvCode.java
+++ b/dx/src/com/android/dx/dex/code/DalvCode.java
@@ -23,7 +23,7 @@
/**
* Container for all the pieces of a concrete method. Each instance
- * corresponds to a <code>code</code> structure in a <code>.dex</code> file.
+ * corresponds to a {@code code} structure in a {@code .dex} file.
*/
public final class DalvCode {
/**
@@ -33,37 +33,37 @@
private final int positionInfo;
/**
- * null-ok; the instruction list, ready for final processing;
+ * {@code null-ok;} the instruction list, ready for final processing;
* nulled out in {@link #finishProcessingIfNecessary}
*/
private OutputFinisher unprocessedInsns;
/**
- * non-null; unprocessed catch table;
+ * {@code non-null;} unprocessed catch table;
* nulled out in {@link #finishProcessingIfNecessary}
*/
private CatchBuilder unprocessedCatches;
/**
- * null-ok; catch table; set in
+ * {@code null-ok;} catch table; set in
* {@link #finishProcessingIfNecessary}
*/
private CatchTable catches;
/**
- * null-ok; source positions list; set in
+ * {@code null-ok;} source positions list; set in
* {@link #finishProcessingIfNecessary}
*/
private PositionList positions;
/**
- * null-ok; local variable list; set in
+ * {@code null-ok;} local variable list; set in
* {@link #finishProcessingIfNecessary}
*/
private LocalList locals;
/**
- * null-ok; the processed instruction list; set in
+ * {@code null-ok;} the processed instruction list; set in
* {@link #finishProcessingIfNecessary}
*/
private DalvInsnList insns;
@@ -73,9 +73,9 @@
*
* @param positionInfo how much position info to preserve; one of the
* static constants in {@link PositionList}
- * @param unprocessedInsns non-null; the instruction list, ready
+ * @param unprocessedInsns {@code non-null;} the instruction list, ready
* for final processing
- * @param unprocessedCatches non-null; unprocessed catch
+ * @param unprocessedCatches {@code non-null;} unprocessed catch
* (exception handler) table
*/
public DalvCode(int positionInfo, OutputFinisher unprocessedInsns,
@@ -120,7 +120,7 @@
* given callback to perform lookups. This must be called before
* {@link #getInsns}.
*
- * @param callback non-null; callback object
+ * @param callback {@code non-null;} callback object
*/
public void assignIndices(AssignIndicesCallback callback) {
unprocessedInsns.assignIndices(callback);
@@ -129,7 +129,7 @@
/**
* Gets whether this instance has any position data to represent.
*
- * @return <code>true</code> iff this instance has any position
+ * @return {@code true} iff this instance has any position
* data to represent
*/
public boolean hasPositions() {
@@ -140,7 +140,7 @@
/**
* Gets whether this instance has any local variable data to represent.
*
- * @return <code>true</code> iff this instance has any local variable
+ * @return {@code true} iff this instance has any local variable
* data to represent
*/
public boolean hasLocals() {
@@ -160,7 +160,7 @@
/**
* Gets the set of catch types handled anywhere in the code.
*
- * @return non-null; the set of catch types
+ * @return {@code non-null;} the set of catch types
*/
public HashSet<Type> getCatchTypes() {
return unprocessedCatches.getCatchTypes();
@@ -170,7 +170,7 @@
* Gets the set of all constants referred to by instructions in
* the code.
*
- * @return non-null; the set of constants
+ * @return {@code non-null;} the set of constants
*/
public HashSet<Constant> getInsnConstants() {
return unprocessedInsns.getAllConstants();
@@ -179,7 +179,7 @@
/**
* Gets the list of instructions.
*
- * @return non-null; the instruction list
+ * @return {@code non-null;} the instruction list
*/
public DalvInsnList getInsns() {
finishProcessingIfNecessary();
@@ -189,7 +189,7 @@
/**
* Gets the catch (exception handler) table.
*
- * @return non-null; the catch table
+ * @return {@code non-null;} the catch table
*/
public CatchTable getCatches() {
finishProcessingIfNecessary();
@@ -199,7 +199,7 @@
/**
* Gets the source positions list.
*
- * @return non-null; the source positions list
+ * @return {@code non-null;} the source positions list
*/
public PositionList getPositions() {
finishProcessingIfNecessary();
@@ -209,7 +209,7 @@
/**
* Gets the source positions list.
*
- * @return non-null; the source positions list
+ * @return {@code non-null;} the source positions list
*/
public LocalList getLocals() {
finishProcessingIfNecessary();
@@ -223,8 +223,8 @@
/**
* Gets the index for the given constant.
*
- * @param cst non-null; the constant
- * @return >= -1; the index or <code>-1</code> if the 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
*/
public int getIndex(Constant cst);
diff --git a/dx/src/com/android/dx/dex/code/DalvInsn.java b/dx/src/com/android/dx/dex/code/DalvInsn.java
index d922193..11ee55d 100644
--- a/dx/src/com/android/dx/dex/code/DalvInsn.java
+++ b/dx/src/com/android/dx/dex/code/DalvInsn.java
@@ -29,26 +29,26 @@
public abstract class DalvInsn {
/**
* the actual output address of this instance, if known, or
- * <code>-1</code> if not
+ * {@code -1} if not
*/
private int address;
/** the opcode; one of the constants from {@link Dops} */
private final Dop opcode;
- /** non-null; source position */
+ /** {@code non-null;} source position */
private final SourcePosition position;
- /** non-null; list of register arguments */
+ /** {@code non-null;} list of register arguments */
private final RegisterSpecList registers;
/**
* Makes a move instruction, appropriate and ideal for the given arguments.
*
- * @param position non-null; source position information
- * @param dest non-null; destination register
- * @param src non-null; source register
- * @return non-null; an appropriately-constructed instance
+ * @param position {@code non-null;} source position information
+ * @param dest {@code non-null;} destination register
+ * @param src {@code non-null;} source register
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static SimpleInsn makeMove(SourcePosition position,
RegisterSpec dest, RegisterSpec src) {
@@ -75,17 +75,17 @@
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
* <p><b>Note:</b> In the unlikely event that an instruction takes
- * absolutely no registers (e.g., a <code>nop</code> or a
+ * 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 non-null; source position
- * @param registers non-null; register list, including a
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
* result register if appropriate (that is, registers may be either
* ins and outs)
*/
@@ -151,11 +151,11 @@
/**
* Gets the output address of this instruction, if it is known. This throws
- * a <code>RuntimeException</code> if it has not yet been set.
+ * a {@code RuntimeException} if it has not yet been set.
*
* @see #setAddress
*
- * @return >= 0; the output address
+ * @return {@code >= 0;} the output address
*/
public final int getAddress() {
if (address < 0) {
@@ -168,7 +168,7 @@
/**
* Gets the opcode.
*
- * @return non-null; the opcode
+ * @return {@code non-null;} the opcode
*/
public final Dop getOpcode() {
return opcode;
@@ -177,7 +177,7 @@
/**
* Gets the source position.
*
- * @return non-null; the source position
+ * @return {@code non-null;} the source position
*/
public final SourcePosition getPosition() {
return position;
@@ -186,7 +186,7 @@
/**
* Gets the register list for this instruction.
*
- * @return non-null; the registers
+ * @return {@code non-null;} the registers
*/
public final RegisterSpecList getRegisters() {
return registers;
@@ -195,9 +195,9 @@
/**
* Returns whether this instance's opcode uses a result register.
* This method is a convenient shorthand for
- * <code>getOpcode().hasResult()</code>.
+ * {@code getOpcode().hasResult()}.
*
- * @return <code>true</code> iff this opcode uses a result register
+ * @return {@code true} iff this opcode uses a result register
*/
public final boolean hasResult() {
return opcode.hasResult();
@@ -210,7 +210,7 @@
* (to be explicit here) category-2 values take up two consecutive
* registers.
*
- * @return >= 0; the minimum distinct register requirement
+ * @return {@code >= 0;} the minimum distinct register requirement
*/
public final int getMinimumRegisterRequirement() {
boolean hasResult = hasResult();
@@ -231,7 +231,7 @@
*
* @see #hrVersion
*
- * @return null-ok; the prefix, if any
+ * @return {@code null-ok;} the prefix, if any
*/
public DalvInsn hrPrefix() {
RegisterSpecList regs = registers;
@@ -255,7 +255,7 @@
*
* @see #hrVersion
*
- * @return null-ok; the suffix, if any
+ * @return {@code null-ok;} the suffix, if any
*/
public DalvInsn hrSuffix() {
if (hasResult()) {
@@ -268,8 +268,8 @@
/**
* Gets the instruction that is equivalent to this one, except that
- * uses sequential registers starting at <code>0</code> (storing
- * the result, if any, in register <code>0</code> as well). The
+ * uses sequential registers starting at {@code 0} (storing
+ * the result, if any, in register {@code 0} as well). The
* sequence of instructions from {@link #hrPrefix} and {@link
* #hrSuffix} (if non-null) surrounding the result of a call to
* this method are the high register transformation of this
@@ -277,7 +277,7 @@
* used will be the number returned by {@link
* #getMinimumRegisterRequirement}.
*
- * @return non-null; the replacement
+ * @return {@code non-null;} the replacement
*/
public DalvInsn hrVersion() {
RegisterSpecList regs =
@@ -289,7 +289,7 @@
* Gets the short identifier for this instruction. This is its
* address, if assigned, or its identity hashcode if not.
*
- * @return non-null; the identifier
+ * @return {@code non-null;} the identifier
*/
public final String identifierString() {
if (address != -1) {
@@ -301,16 +301,16 @@
/**
* Returns the string form of this instance suitable for inclusion in
- * a human-oriented listing dump. This method will return <code>null</code>
+ * a human-oriented listing dump. This method will return {@code null}
* if this instance should not appear in a listing.
*
- * @param prefix non-null; prefix before the address; each follow-on
+ * @param prefix {@code non-null;} prefix before the address; each follow-on
* line will be indented to match as well
- * @param width >= 0; the width of the output or <code>0</code> for
+ * @param width {@code >= 0;} the width of the output or {@code 0} for
* unlimited width
* @param noteIndices whether to include an explicit notation of
* constant pool indices
- * @return null-ok; the string form or <code>null</code> if this
+ * @return {@code null-ok;} the string form or {@code null} if this
* instance should not appear in a listing
*/
public final String listingString(String prefix, int width,
@@ -331,7 +331,7 @@
/**
* Sets the output address.
*
- * @param address >= 0; the output address
+ * @param address {@code >= 0;} the output address
*/
public final void setAddress(int address) {
if (address < 0) {
@@ -347,7 +347,7 @@
* to the address plus the length of the instruction format of this
* instance's opcode.
*
- * @return >= 0; the next address
+ * @return {@code >= 0;} the next address
*/
public final int getNextAddress() {
return getAddress() + codeSize();
@@ -356,7 +356,7 @@
/**
* Gets the size of this instruction, in 16-bit code units.
*
- * @return >= 0; the code size of this instruction
+ * @return {@code >= 0;} the code size of this instruction
*/
public abstract int codeSize();
@@ -364,7 +364,7 @@
* Writes this instance to the given output. This method should
* never annotate the output.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
*/
public abstract void writeTo(AnnotatedOutput out);
@@ -372,8 +372,8 @@
* 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 non-null; the new opcode
- * @return non-null; an appropriately-constructed instance
+ * @param opcode {@code non-null;} the new opcode
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public abstract DalvInsn withOpcode(Dop opcode);
@@ -383,7 +383,7 @@
* address is reset.
*
* @param delta the amount to offset register references by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public abstract DalvInsn withRegisterOffset(int delta);
@@ -392,8 +392,8 @@
* register list is replaced by the given one, and its address is
* reset.
*
- * @param registers non-null; new register list
- * @return non-null; an appropriately-constructed instance
+ * @param registers {@code non-null;} new register list
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public abstract DalvInsn withRegisters(RegisterSpecList registers);
@@ -401,8 +401,8 @@
* Gets the string form for any arguments to this instance. Subclasses
* must override this.
*
- * @return null-ok; the string version of any arguments or
- * <code>null</code> if there are none
+ * @return {@code null-ok;} the string version of any arguments or
+ * {@code null} if there are none
*/
protected abstract String argString();
@@ -411,12 +411,12 @@
* form of this instance suitable for inclusion in a
* human-oriented listing dump, not including the instruction
* address and without respect for any output formatting. This
- * method should return <code>null</code> if this instance should
+ * 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 null-ok; the listing string
+ * @return {@code null-ok;} the listing string
*/
protected abstract String listingString0(boolean noteIndices);
}
diff --git a/dx/src/com/android/dx/dex/code/DalvInsnList.java b/dx/src/com/android/dx/dex/code/DalvInsnList.java
index 2cd15c6..5cf22f2 100644
--- a/dx/src/com/android/dx/dex/code/DalvInsnList.java
+++ b/dx/src/com/android/dx/dex/code/DalvInsnList.java
@@ -46,10 +46,10 @@
* Constructs and returns an immutable instance whose elements are
* identical to the ones in the given list, in the same order.
*
- * @param list non-null; the list to use for elements
+ * @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.
- * @return non-null; an appropriately-constructed instance of this
+ * @return {@code non-null;} an appropriately-constructed instance of this
* class
*/
public static DalvInsnList makeImmutable(ArrayList<DalvInsn> list,
@@ -66,7 +66,7 @@
}
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -78,10 +78,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public DalvInsn get(int n) {
return (DalvInsn) get0(n);
@@ -90,8 +90,8 @@
/**
* Sets the instruction at the given index.
*
- * @param n >= 0, < size(); which index
- * @param insn non-null; the instruction to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param insn {@code non-null;} the instruction to set at {@code n}
*/
public void set(int n, DalvInsn insn) {
set0(n, insn);
@@ -102,7 +102,7 @@
* return a meaningful result if the instructions in this instance all
* have valid addresses.
*
- * @return >= 0; the size
+ * @return {@code >= 0;} the size
*/
public int codeSize() {
int sz = size();
@@ -119,7 +119,7 @@
* Writes all the instructions in this instance to the given output
* destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
*/
public void writeTo(AnnotatedOutput out) {
int startCursor = out.getCursor();
@@ -170,7 +170,7 @@
* Gets the minimum required register count implied by this
* instance. This includes any unused parameters that could
* potentially be at the top of the register space.
- * @return >= 0; the required registers size
+ * @return {@code >= 0;} the required registers size
*/
public int getRegistersSize() {
return regCount;
@@ -181,7 +181,7 @@
* method. This is equal to the largest argument word count of any
* method referred to by this instance.
*
- * @return >= 0; the required outgoing arguments size
+ * @return {@code >= 0;} the required outgoing arguments size
*/
public int getOutsSize() {
int sz = size();
@@ -216,8 +216,8 @@
/**
* Does a human-friendly dump of this instance.
*
- * @param out non-null; where to dump
- * @param prefix non-null; prefix to attach to each line of output
+ * @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
* lines for zero-size instructions and explicit constant pool indices
*/
@@ -250,8 +250,8 @@
/**
* Does a human-friendly dump of this instance.
*
- * @param out non-null; where to dump
- * @param prefix non-null; prefix to attach to each line of output
+ * @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
* lines for zero-size instructions
*/
diff --git a/dx/src/com/android/dx/dex/code/Dop.java b/dx/src/com/android/dx/dex/code/Dop.java
index 6914fca..d1f92bf 100644
--- a/dx/src/com/android/dx/dex/code/Dop.java
+++ b/dx/src/com/android/dx/dex/code/Dop.java
@@ -26,25 +26,25 @@
/** DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family */
private final int family;
- /** non-null; the instruction format */
+ /** {@code non-null;} the instruction format */
private final InsnFormat format;
/** whether this opcode uses a result register */
private final boolean hasResult;
- /** non-null; the name */
+ /** {@code non-null;} the name */
private final String name;
/**
* Constructs an instance.
*
- * @param opcode DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode
+ * @param opcode {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode
* value itself
- * @param family DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family
- * @param format non-null; the instruction format
+ * @param family {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
+ * @param format {@code non-null;} the instruction format
* @param hasResult whether the opcode has a result register; if so it
* is always the first register
- * @param name non-null; the name
+ * @param name {@code non-null;} the name
*/
public Dop(int opcode, int family, InsnFormat format,
boolean hasResult, String name) {
@@ -80,7 +80,7 @@
/**
* Gets the opcode value.
*
- * @return DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode value
+ * @return {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode value
*/
public int getOpcode() {
return opcode;
@@ -90,7 +90,7 @@
* Gets the opcode family. The opcode family is the unmarked (no
* "/...") opcode that has equivalent semantics to this one.
*
- * @return DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family
+ * @return {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode family
*/
public int getFamily() {
return family;
@@ -99,7 +99,7 @@
/**
* Gets the instruction format.
*
- * @return non-null; the instruction format
+ * @return {@code non-null;} the instruction format
*/
public InsnFormat getFormat() {
return format;
@@ -108,7 +108,7 @@
/**
* Returns whether this opcode uses a result register.
*
- * @return <code>true</code> iff this opcode uses a result register
+ * @return {@code true} iff this opcode uses a result register
*/
public boolean hasResult() {
return hasResult;
@@ -117,7 +117,7 @@
/**
* Gets the opcode name.
*
- * @return non-null; the opcode name
+ * @return {@code non-null;} the opcode name
*/
public String getName() {
return name;
@@ -127,7 +127,7 @@
* Gets the opcode for the opposite test of this instance. This is only
* valid for opcodes which are in fact tests.
*
- * @return non-null; the opposite test
+ * @return {@code non-null;} the opposite test
*/
public Dop getOppositeTest() {
switch (opcode) {
diff --git a/dx/src/com/android/dx/dex/code/Dops.java b/dx/src/com/android/dx/dex/code/Dops.java
index 8923c59..dfdaa73 100644
--- a/dx/src/com/android/dx/dex/code/Dops.java
+++ b/dx/src/com/android/dx/dex/code/Dops.java
@@ -47,7 +47,7 @@
* them.
*/
public final class Dops {
- /** non-null; array containing all the standard instances */
+ /** {@code non-null;} array containing all the standard instances */
private static final Dop[] DOPS;
/**
@@ -1172,8 +1172,8 @@
/**
* Gets the {@link Dop} for the given opcode value.
*
- * @param opcode DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode value
- * @return non-null; the associated opcode instance
+ * @param opcode {@code DalvOps.MIN_VALUE..DalvOps.MAX_VALUE;} the opcode value
+ * @return {@code non-null;} the associated opcode instance
*/
public static Dop get(int opcode) {
int idx = opcode - DalvOps.MIN_VALUE;
@@ -1194,9 +1194,9 @@
* Gets the {@link Dop} with the given family/format combination, if
* any.
*
- * @param family DalvOps.MIN_VALUE..DalvOps.MAX_VALUE; the opcode family
- * @param format non-null; the opcode's instruction format
- * @return null-ok; the corresponding opcode, or <code>null</code> if
+ * @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
* there is none
*/
public static Dop getOrNull(int family, InsnFormat format) {
@@ -1222,7 +1222,7 @@
/**
* Puts the given opcode into the table of all ops.
*
- * @param opcode non-null; the opcode
+ * @param opcode {@code non-null;} the opcode
*/
private static void set(Dop opcode) {
int idx = opcode.getOpcode() - DalvOps.MIN_VALUE;
diff --git a/dx/src/com/android/dx/dex/code/FixedSizeInsn.java b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
index 63c9d24..147937f 100644
--- a/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
+++ b/dx/src/com/android/dx/dex/code/FixedSizeInsn.java
@@ -28,17 +28,17 @@
public abstract class FixedSizeInsn extends DalvInsn {
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
* <p><b>Note:</b> In the unlikely event that an instruction takes
- * absolutely no registers (e.g., a <code>nop</code> or a
+ * 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 non-null; source position
- * @param registers non-null; register list, including a
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
* result register if appropriate (that is, registers may be either
* ins or outs)
*/
diff --git a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
index 458bc89..9155367 100644
--- a/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
+++ b/dx/src/com/android/dx/dex/code/HighRegisterPrefix.java
@@ -24,21 +24,21 @@
/**
* Combination instruction which turns into a variable number of
- * <code>move*</code> instructions to move a set of registers into
- * registers starting at <code>0</code> sequentially. This is used
+ * {@code move*} instructions to move a set of registers into
+ * registers starting at {@code 0} sequentially. This is used
* in translating an instruction whose register requirements cannot
* be met using a straightforward choice of a single opcode.
*/
public final class HighRegisterPrefix extends VariableSizeInsn {
- /** null-ok; cached instructions, if constructed */
+ /** {@code null-ok;} cached instructions, if constructed */
private SimpleInsn[] insns;
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param registers non-null; source registers
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} source registers
*/
public HighRegisterPrefix(SourcePosition position,
RegisterSpecList registers) {
@@ -135,9 +135,9 @@
* Returns the proper move instruction for the given source spec
* and destination index.
*
- * @param src non-null; the source register spec
- * @param destIndex >= 0; the destination register index
- * @return non-null; the appropriate move instruction
+ * @param src {@code non-null;} the source register spec
+ * @param destIndex {@code >= 0;} the destination register index
+ * @return {@code non-null;} the appropriate move instruction
*/
private static SimpleInsn moveInsnFor(RegisterSpec src, int destIndex) {
return DalvInsn.makeMove(SourcePosition.NO_INFO,
diff --git a/dx/src/com/android/dx/dex/code/InsnFormat.java b/dx/src/com/android/dx/dex/code/InsnFormat.java
index ed4137b..ca6688b 100644
--- a/dx/src/com/android/dx/dex/code/InsnFormat.java
+++ b/dx/src/com/android/dx/dex/code/InsnFormat.java
@@ -37,10 +37,10 @@
* dump, of the given instruction. The instruction must be of this
* instance's format for proper operation.
*
- * @param insn non-null; the instruction
+ * @param insn {@code non-null;} the instruction
* @param noteIndices whether to include an explicit notation of
* constant pool indices
- * @return non-null; the string form
+ * @return {@code non-null;} the string form
*/
public final String listingString(DalvInsn insn, boolean noteIndices) {
String op = insn.getOpcode().getName();
@@ -66,28 +66,28 @@
/**
* Returns the string form of the arguments to the given instruction.
* The instruction must be of this instance's format. If the instruction
- * has no arguments, then the result should be <code>""</code>, not
- * <code>null</code>.
+ * has no arguments, then the result should be {@code ""}, not
+ * {@code null}.
*
* <p>Subclasses must override this method.</p>
*
- * @param insn non-null; the instruction
- * @return non-null; the string form
+ * @param insn {@code non-null;} the instruction
+ * @return {@code non-null;} the string form
*/
public abstract String insnArgString(DalvInsn insn);
/**
* Returns the associated comment for the given instruction, if any.
* The instruction must be of this instance's format. If the instruction
- * has no comment, then the result should be <code>""</code>, not
- * <code>null</code>.
+ * has no comment, then the result should be {@code ""}, not
+ * {@code null}.
*
* <p>Subclasses must override this method.</p>
*
- * @param insn non-null; the instruction
+ * @param insn {@code non-null;} the instruction
* @param noteIndices whether to include an explicit notation of
* constant pool indices
- * @return non-null; the string form
+ * @return {@code non-null;} the string form
*/
public abstract String insnCommentString(DalvInsn insn,
boolean noteIndices);
@@ -97,7 +97,7 @@
* size is a number of 16-bit code units, not bytes. This should
* throw an exception if this format is of variable size.
*
- * @return >= 0; the instruction length in 16-bit code units
+ * @return {@code >= 0;} the instruction length in 16-bit code units
*/
public abstract int codeSize();
@@ -112,24 +112,24 @@
*
* <p>Subclasses must override this method.</p>
*
- * @param insn non-null; the instruction to check
- * @return <code>true</code> iff the instruction's arguments are
- * appropriate for this instance, or <code>false</code> if not
+ * @param insn {@code non-null;} the instruction to check
+ * @return {@code true} iff the instruction's arguments are
+ * appropriate for this instance, or {@code false} if not
*/
public abstract boolean isCompatible(DalvInsn insn);
/**
* Returns whether or not the given instruction's branch offset will
- * fit in this instance's format. This always returns <code>false</code>
+ * fit in this instance's format. This always returns {@code false}
* for formats that don't include a branch offset.
*
* <p>The default implementation of this method always returns
- * <code>false</code>. Subclasses must override this method if they
+ * {@code false}. Subclasses must override this method if they
* include branch offsets.</p>
*
- * @param insn non-null; the instruction to check
- * @return <code>true</code> iff the instruction's branch offset is
- * appropriate for this instance, or <code>false</code> if not
+ * @param insn {@code non-null;} the instruction to check
+ * @return {@code true} iff the instruction's branch offset is
+ * appropriate for this instance, or {@code false} if not
*/
public boolean branchFits(TargetInsn insn) {
return false;
@@ -141,7 +141,7 @@
*
* <p>Subclasses must override this method.</p>
*
- * @return null-ok; the next format to try, or <code>null</code> if
+ * @return {@code null-ok;} the next format to try, or {@code null} if
* there are no suitable alternatives
*/
public abstract InsnFormat nextUp();
@@ -152,16 +152,16 @@
*
* <p>Subclasses must override this method.</p>
*
- * @param out non-null; the output destination to write to
- * @param insn non-null; the instruction to write
+ * @param out {@code non-null;} the output destination to write to
+ * @param insn {@code non-null;} the instruction to write
*/
public abstract void writeTo(AnnotatedOutput out, DalvInsn insn);
/**
* Helper method to return a register list string.
*
- * @param list non-null; the list of registers
- * @return non-null; the string form
+ * @param list {@code non-null;} the list of registers
+ * @return {@code non-null;} the string form
*/
protected static String regListString(RegisterSpecList list) {
int sz = list.size();
@@ -185,7 +185,7 @@
* Helper method to return a literal bits argument string.
*
* @param value the value
- * @return non-null; the string form
+ * @return {@code non-null;} the string form
*/
protected static String literalBitsString(CstLiteralBits value) {
StringBuffer sb = new StringBuffer(100);
@@ -208,8 +208,8 @@
*
* @param value the value
* @param width the width of the constant, in bits (used for displaying
- * the uninterpreted bits; one of: <code>4 8 16 32 64</code>
- * @return non-null; the comment
+ * the uninterpreted bits; one of: {@code 4 8 16 32 64}
+ * @return {@code non-null;} the comment
*/
protected static String literalBitsComment(CstLiteralBits value,
int width) {
@@ -242,8 +242,8 @@
/**
* Helper method to return a branch address string.
*
- * @param insn non-null; the instruction in question
- * @return non-null; the string form of the instruction's branch target
+ * @param insn {@code non-null;} the instruction in question
+ * @return {@code non-null;} the string form of the instruction's branch target
*/
protected static String branchString(DalvInsn insn) {
TargetInsn ti = (TargetInsn) insn;
@@ -255,8 +255,8 @@
/**
* Helper method to return the comment for a branch.
*
- * @param insn non-null; the instruction in question
- * @return non-null; the comment
+ * @param insn {@code non-null;} the instruction in question
+ * @return {@code non-null;} the comment
*/
protected static String branchComment(DalvInsn insn) {
TargetInsn ti = (TargetInsn) insn;
@@ -268,8 +268,8 @@
/**
* Helper method to return a constant string.
*
- * @param insn non-null; a constant-bearing instruction
- * @return non-null; the string form of the contained constant
+ * @param insn {@code non-null;} a constant-bearing instruction
+ * @return {@code non-null;} the string form of the contained constant
*/
protected static String cstString(DalvInsn insn) {
CstInsn ci = (CstInsn) insn;
@@ -281,8 +281,8 @@
/**
* Helper method to return an instruction comment for a constant.
*
- * @param insn non-null; a constant-bearing instruction
- * @return non-null; comment string representing the constant
+ * @param insn {@code non-null;} a constant-bearing instruction
+ * @return {@code non-null;} comment string representing the constant
*/
protected static String cstComment(DalvInsn insn) {
CstInsn ci = (CstInsn) insn;
@@ -310,7 +310,7 @@
* Helper method to determine if a signed int value fits in a nibble.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range -8..+7
+ * @return {@code true} iff it's in the range -8..+7
*/
protected static boolean signedFitsInNibble(int value) {
return (value >= -8) && (value <= 7);
@@ -320,7 +320,7 @@
* Helper method to determine if an unsigned int value fits in a nibble.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range 0..0xf
+ * @return {@code true} iff it's in the range 0..0xf
*/
protected static boolean unsignedFitsInNibble(int value) {
return value == (value & 0xf);
@@ -330,7 +330,7 @@
* Helper method to determine if a signed int value fits in a byte.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range -0x80..+0x7f
+ * @return {@code true} iff it's in the range -0x80..+0x7f
*/
protected static boolean signedFitsInByte(int value) {
return (byte) value == value;
@@ -340,7 +340,7 @@
* Helper method to determine if an unsigned int value fits in a byte.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range 0..0xff
+ * @return {@code true} iff it's in the range 0..0xff
*/
protected static boolean unsignedFitsInByte(int value) {
return value == (value & 0xff);
@@ -350,7 +350,7 @@
* Helper method to determine if a signed int value fits in a short.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range -0x8000..+0x7fff
+ * @return {@code true} iff it's in the range -0x8000..+0x7fff
*/
protected static boolean signedFitsInShort(int value) {
return (short) value == value;
@@ -360,7 +360,7 @@
* Helper method to determine if an unsigned int value fits in a short.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range 0..0xffff
+ * @return {@code true} iff it's in the range 0..0xffff
*/
protected static boolean unsignedFitsInShort(int value) {
return value == (value & 0xffff);
@@ -370,7 +370,7 @@
* Helper method to determine if a signed int value fits in three bytes.
*
* @param value the value in question
- * @return <code>true</code> iff it's in the range -0x800000..+0x7fffff
+ * @return {@code true} iff it's in the range -0x800000..+0x7fffff
*/
protected static boolean signedFitsIn3Bytes(int value) {
return value == ((value << 8) >> 8);
@@ -380,8 +380,8 @@
* Helper method to extract the callout-argument index from an
* appropriate instruction.
*
- * @param insn non-null; the instruction
- * @return >= 0; the callout argument index
+ * @param insn {@code non-null;} the instruction
+ * @return {@code >= 0;} the callout argument index
*/
protected static int argIndex(DalvInsn insn) {
int arg = ((CstInteger) ((CstInsn) insn).getConstant()).getValue();
@@ -397,8 +397,8 @@
* Helper method to combine an opcode and a second byte of data into
* the appropriate form for emitting into a code buffer.
*
- * @param insn non-null; the instruction containing the opcode
- * @param arg 0..255; arbitrary other byte value
+ * @param insn {@code non-null;} the instruction containing the opcode
+ * @param arg {@code 0..255;} arbitrary other byte value
* @return combined value
*/
protected static short opcodeUnit(DalvInsn insn, int arg) {
@@ -418,8 +418,8 @@
/**
* Helper method to combine two bytes into a code unit.
*
- * @param low 0..255; low byte
- * @param high 0..255; high byte
+ * @param low {@code 0..255;} low byte
+ * @param high {@code 0..255;} high byte
* @return combined value
*/
protected static short codeUnit(int low, int high) {
@@ -437,10 +437,10 @@
/**
* Helper method to combine four nibbles into a code unit.
*
- * @param n0 0..15; low nibble
- * @param n1 0..15; medium-low nibble
- * @param n2 0..15; medium-high nibble
- * @param n3 0..15; high nibble
+ * @param n0 {@code 0..15;} low nibble
+ * @param n1 {@code 0..15;} medium-low nibble
+ * @param n2 {@code 0..15;} medium-high nibble
+ * @param n3 {@code 0..15;} high nibble
* @return combined value
*/
protected static short codeUnit(int n0, int n1, int n2, int n3) {
@@ -466,9 +466,9 @@
/**
* Helper method to combine two nibbles into a byte.
*
- * @param low 0..15; low nibble
- * @param high 0..15; high nibble
- * @return 0..255; combined value
+ * @param low {@code 0..15;} low nibble
+ * @param high {@code 0..15;} high nibble
+ * @return {@code 0..255;} combined value
*/
protected static int makeByte(int low, int high) {
if ((low & 0xf) != low) {
@@ -485,7 +485,7 @@
/**
* Writes one code unit to the given output destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
* @param c0 code unit to write
*/
protected static void write(AnnotatedOutput out, short c0) {
@@ -495,7 +495,7 @@
/**
* Writes two code units to the given output destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
*/
@@ -507,7 +507,7 @@
/**
* Writes three code units to the given output destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
* @param c2 code unit to write
@@ -522,7 +522,7 @@
/**
* Writes four code units to the given output destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
* @param c2 code unit to write
@@ -539,7 +539,7 @@
/**
* Writes five code units to the given output destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
* @param c2 code unit to write
@@ -558,7 +558,7 @@
/**
* Writes six code units to the given output destination.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
* @param c0 code unit to write
* @param c1 code unit to write
* @param c2 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 c19a8dc..360a55c 100644
--- a/dx/src/com/android/dx/dex/code/LocalEnd.java
+++ b/dx/src/com/android/dx/dex/code/LocalEnd.java
@@ -28,7 +28,7 @@
*/
public final class LocalEnd extends ZeroSizeInsn {
/**
- * non-null; register spec representing the local variable ended
+ * {@code non-null;} register spec representing the local variable ended
* by this instance. <b>Note:</b> Technically, only the register
* number needs to be recorded here as the rest of the information
* is implicit in the ambient local variable state, but other code
@@ -38,10 +38,10 @@
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param local non-null; register spec representing the local
+ * @param position {@code non-null;} source position
+ * @param local {@code non-null;} register spec representing the local
* variable introduced by this instance
*/
public LocalEnd(SourcePosition position, RegisterSpec local) {
@@ -70,7 +70,7 @@
* Gets the register spec representing the local variable ended
* by this instance.
*
- * @return non-null; the register spec
+ * @return {@code non-null;} the register spec
*/
public RegisterSpec getLocal() {
return local;
diff --git a/dx/src/com/android/dx/dex/code/LocalList.java b/dx/src/com/android/dx/dex/code/LocalList.java
index 4614fc4..93e7c3f 100644
--- a/dx/src/com/android/dx/dex/code/LocalList.java
+++ b/dx/src/com/android/dx/dex/code/LocalList.java
@@ -33,16 +33,16 @@
* and a type.
*/
public final class LocalList extends FixedSizeList {
- /** non-null; empty instance */
+ /** {@code non-null;} empty instance */
public static final LocalList EMPTY = new LocalList(0);
/** whether to run the self-check code */
private static final boolean DEBUG = false;
-
+
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
- *
- * @param size >= 0; the size of the list
+ * Constructs an instance. All indices initially contain {@code null}.
+ *
+ * @param size {@code >= 0;} the size of the list
*/
public LocalList(int size) {
super(size);
@@ -51,10 +51,10 @@
/**
* 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</code>.
- *
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * do that, this will throw {@code NullPointerException}.
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Entry get(int n) {
return (Entry) get0(n);
@@ -62,9 +62,9 @@
/**
* Sets the entry at the given index.
- *
- * @param n >= 0, < size(); which index
- * @param entry non-null; the entry to set at <code>n</code>
+ *
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
*/
public void set(int n, Entry entry) {
set0(n, entry);
@@ -72,9 +72,9 @@
/**
* Does a human-friendly dump of this instance.
- *
- * @param out non-null; where to dump
- * @param prefix non-null; prefix to attach to each line of output
+ *
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
*/
public void debugPrint(PrintStream out, String prefix) {
int sz = size();
@@ -90,7 +90,7 @@
*/
public static enum Disposition {
/** local started (introduced) */
- START,
+ START,
/** local ended without being replaced */
END_SIMPLY,
@@ -118,24 +118,25 @@
* Entry in a local list.
*/
public static class Entry implements Comparable<Entry> {
- /** >= 0; address */
+ /** {@code >= 0;} address */
private final int address;
- /** non-null; disposition of the local */
+ /** {@code non-null;} disposition of the local */
private final Disposition disposition;
- /** non-null; register spec representing the variable */
+ /** {@code non-null;} register spec representing the variable */
private final RegisterSpec spec;
- /** non-null; variable type (derived from {@code spec}) */
+ /** {@code non-null;} variable type (derived from {@code spec}) */
private final CstType type;
-
+
/**
* Constructs an instance.
- *
- * @param address >= 0; address
- * @param disposition non-null; disposition of the local
- * @param spec non-null; register spec representing the variable
+ *
+ * @param address {@code >= 0;} address
+ * @param disposition {@code non-null;} disposition of the local
+ * @param spec {@code non-null;} register spec representing
+ * the variable
*/
public Entry(int address, Disposition disposition, RegisterSpec spec) {
if (address < 0) {
@@ -181,9 +182,9 @@
* Compares by (in priority order) address, end then start
* disposition (variants of end are all consistered
* equivalent), and spec.
- *
- * @param other non-null; entry to compare to
- * @return {@code -1..1}; standard result of comparison
+ *
+ * @param other {@code non-null;} entry to compare to
+ * @return {@code -1..1;} standard result of comparison
*/
public int compareTo(Entry other) {
if (address < other.address) {
@@ -194,7 +195,7 @@
boolean thisIsStart = isStart();
boolean otherIsStart = other.isStart();
-
+
if (thisIsStart != otherIsStart) {
return thisIsStart ? 1 : -1;
}
@@ -204,8 +205,8 @@
/**
* Gets the address.
- *
- * @return >= 0; the address
+ *
+ * @return {@code >= 0;} the address
*/
public int getAddress() {
return address;
@@ -213,8 +214,8 @@
/**
* Gets the disposition.
- *
- * @return non-null; the disposition
+ *
+ * @return {@code non-null;} the disposition
*/
public Disposition getDisposition() {
return disposition;
@@ -223,7 +224,7 @@
/**
* Gets whether this is a local start. This is just shorthand for
* {@code getDisposition() == Disposition.START}.
- *
+ *
* @return {@code true} iff this is a start
*/
public boolean isStart() {
@@ -232,8 +233,8 @@
/**
* Gets the variable name.
- *
- * @return null-ok; the variable name
+ *
+ * @return {@code null-ok;} the variable name
*/
public CstUtf8 getName() {
return spec.getLocalItem().getName();
@@ -242,7 +243,7 @@
/**
* Gets the variable signature.
*
- * @return null-ok; the variable signature
+ * @return {@code null-ok;} the variable signature
*/
public CstUtf8 getSignature() {
return spec.getLocalItem().getSignature();
@@ -250,8 +251,8 @@
/**
* Gets the variable's type.
- *
- * @return non-null; the type
+ *
+ * @return {@code non-null;} the type
*/
public CstType getType() {
return type;
@@ -259,8 +260,9 @@
/**
* Gets the number of the register holding the variable.
- *
- * @return >= 0; the number fo the register holding the variable
+ *
+ * @return {@code >= 0;} the number of the register holding
+ * the variable
*/
public int getRegister() {
return spec.getReg();
@@ -269,7 +271,7 @@
/**
* Gets the RegisterSpec of the register holding the variable.
*
- * @return non-null; RegisterSpec of the holding register.
+ * @return {@code non-null;} RegisterSpec of the holding register.
*/
public RegisterSpec getRegisterSpec() {
return spec;
@@ -277,10 +279,10 @@
/**
* Returns whether or not this instance matches the given spec.
- *
- * @param spec non-null; the spec in question
- * @return <code>true</code> iff this instance matches
- * <code>spec</code>
+ *
+ * @param spec {@code non-null;} the spec in question
+ * @return {@code true} iff this instance matches
+ * {@code spec}
*/
public boolean matches(RegisterSpec otherSpec) {
return spec.equalsUsingSimpleType(otherSpec);
@@ -290,9 +292,9 @@
* Returns whether or not this instance matches the spec in
* the given instance.
*
- * @param other non-null; another entry
- * @return <code>true</code> iff this instance's spec matches
- * <code>other</code>
+ * @param other {@code non-null;} another entry
+ * @return {@code true} iff this instance's spec matches
+ * {@code other}
*/
public boolean matches(Entry other) {
return matches(other.spec);
@@ -300,26 +302,26 @@
/**
* Returns an instance just like this one but with the disposition
- * set as given
- *
- * @param disposition non-null; the new disposition
- * @return non-null; an appropriately-constructed instance
+ * set as given.
+ *
+ * @param disposition {@code non-null;} the new disposition
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public Entry withDisposition(Disposition disposition) {
if (disposition == this.disposition) {
return this;
}
-
+
return new Entry(address, disposition, spec);
}
}
-
+
/**
* Constructs an instance for the given method, based on the given
* block order and intermediate local information.
- *
- * @param insns non-null; instructions to convert
- * @return non-null; the constructed list
+ *
+ * @param insns {@code non-null;} instructions to convert
+ * @return {@code non-null;} the constructed list
*/
public static LocalList make(DalvInsnList insns) {
int sz = insns.size();
@@ -330,8 +332,8 @@
* into separate per-variable starts, adding explicit ends
* wherever a variable is replaced or moved, and collecting
* these and all the other local variable "activity"
- * together into an output list (without the other insns).
- *
+ * together into an output list (without the other insns).
+ *
* Note: As of this writing, this method won't be handed any
* insn lists that contain local ends, but I (danfuzz) expect
* that to change at some point, when we start feeding that
@@ -382,9 +384,9 @@
}
throw ex;
}
-
+
}
-
+
/**
* Helper for {@link #debugVerify} which does most of the work.
*/
@@ -411,7 +413,7 @@
throw new RuntimeException("redundant end at " +
Integer.toHexString(e.getAddress()));
}
-
+
int addr = e.getAddress();
boolean foundStart = false;
@@ -433,7 +435,7 @@
throw new RuntimeException(
"redundant end at " +
Integer.toHexString(addr));
- }
+ }
}
}
@@ -443,7 +445,7 @@
"improper end replacement claim at " +
Integer.toHexString(addr));
}
-
+
active[reg] = null;
}
}
@@ -453,31 +455,25 @@
* Intermediate state when constructing a local list.
*/
public static class MakeState {
- /** non-null; result being collected */
+ /** {@code non-null;} result being collected */
private final ArrayList<Entry> result;
/**
- * >= 0; running count of nulled result entries, to help with
+ * {@code >= 0;} running count of nulled result entries, to help with
* sizing the final list
*/
private int nullResultCount;
- /** null-ok; current register mappings */
+ /** {@code null-ok;} current register mappings */
private RegisterSpecSet regs;
- /** null-ok; result indices where local ends are stored */
+ /** {@code null-ok;} result indices where local ends are stored */
private int[] endIndices;
- /** >= 0; last address seen */
+ /** {@code >= 0;} last address seen */
private int lastAddress;
/**
- * >= 0; result index where the first element for the most
- * recent address is stored
- */
- private int startIndexForAddress;
-
- /**
* Constructs an instance.
*/
public MakeState(int initialSize) {
@@ -486,19 +482,18 @@
regs = null;
endIndices = null;
lastAddress = 0;
- startIndexForAddress = 0;
}
/**
* Checks the address and other vitals as a prerequisite to
* further processing.
*
- * @param address >= 0; address about to be processed
- * @param reg >= 0; register number about to be processed
+ * @param address {@code >= 0;} address about to be processed
+ * @param reg {@code >= 0;} register number about to be processed
*/
private void aboutToProcess(int address, int reg) {
boolean first = (endIndices == null);
-
+
if ((address == lastAddress) && !first) {
return;
}
@@ -534,11 +529,15 @@
* Sets the local state at the given address to the given snapshot.
* The first call on this instance must be to this method, so that
* the register state can be properly sized.
- *
- * @param address >= 0; the address
- * @param specs non-null; spec set representing the locals
+ *
+ * @param address {@code >= 0;} the address
+ * @param specs {@code non-null;} spec set representing the locals
*/
public void snapshot(int address, RegisterSpecSet specs) {
+ if (DEBUG) {
+ System.err.printf("%04x snapshot %s\n", address, specs);
+ }
+
int sz = specs.getMaxSize();
aboutToProcess(address, sz - 1);
@@ -557,15 +556,24 @@
startLocal(address, newSpec);
}
}
+
+ if (DEBUG) {
+ System.err.printf("%04x snapshot done\n", address);
+ }
}
-
+
/**
* Starts a local at the given address.
- *
- * @param address >= 0; the address
- * @param startedLocal non-null; spec representing the started local
+ *
+ * @param address {@code >= 0;} the address
+ * @param startedLocal {@code non-null;} spec representing the
+ * started local
*/
public void startLocal(int address, RegisterSpec startedLocal) {
+ if (DEBUG) {
+ System.err.printf("%04x start %s\n", address, startedLocal);
+ }
+
int regNum = startedLocal.getReg();
startedLocal = filterSpec(startedLocal);
@@ -588,7 +596,7 @@
}
int endAt = endIndices[regNum];
-
+
if (existingLocal != null) {
/*
* There is an existing (but non-matching) local.
@@ -633,8 +641,8 @@
}
}
}
-
- /*
+
+ /*
* The code above didn't find and remove an unnecessary
* local end, so we now have to add one or more entries to
* the output to capture the transition.
@@ -672,17 +680,36 @@
* if any (that is, if the local migrates from vX to vY,
* we should note that as a local end in vX).
*/
-
+
add(address, Disposition.START, startedLocal);
}
/**
+ * Ends a local at the given address, using the disposition
+ * {@code END_SIMPLY}.
+ *
+ * @param address {@code >= 0;} the address
+ * @param endedLocal {@code non-null;} spec representing the
+ * local being ended
+ */
+ public void endLocal(int address, RegisterSpec endedLocal) {
+ endLocal(address, endedLocal, Disposition.END_SIMPLY);
+ }
+
+ /**
* Ends a local at the given address.
*
- * @param address >= 0; the address
- * @param endedLocal non-null; spec representing the local being ended
+ * @param address {@code >= 0;} the address
+ * @param endedLocal {@code non-null;} spec representing the
+ * local being ended
+ * @param disposition reason for the end
*/
- public void endLocal(int address, RegisterSpec endedLocal) {
+ public void endLocal(int address, RegisterSpec endedLocal,
+ Disposition disposition) {
+ if (DEBUG) {
+ System.err.printf("%04x end %s\n", address, endedLocal);
+ }
+
int regNum = endedLocal.getReg();
endedLocal = filterSpec(endedLocal);
@@ -703,7 +730,7 @@
return;
}
- add(address, Disposition.END_SIMPLY, endedLocal);
+ add(address, disposition, endedLocal);
}
/**
@@ -714,9 +741,10 @@
* active), update the {@link #endIndices} to be accurate, and
* if needed update the newly-active end to reflect an altered
* disposition.
- *
- * @param address >= 0; the address
- * @param endedLocal non-null; spec representing the local being ended
+ *
+ * @param address {@code >= 0;} the address
+ * @param endedLocal {@code non-null;} spec representing the
+ * local being ended
* @return {@code true} iff this method found the case in question
* and adjusted things accordingly
*/
@@ -747,7 +775,7 @@
* In fact, we found that the endedLocal had started at the
* same address, so do all the requisite cleanup.
*/
-
+
regs.remove(endedLocal);
result.set(at, null);
nullResultCount++;
@@ -773,7 +801,7 @@
if (found) {
// We found an end for the same register.
endIndices[regNum] = at;
-
+
if (entry.getAddress() == address) {
/*
* It's still the same address, so update the
@@ -793,13 +821,13 @@
* null" type into simply {@code Object}. This method needs to
* be called for any spec that is on its way into a locals
* list.
- *
+ *
* <p>This isn't necessarily the cleanest way to achieve the
* goal of not representing known nulls in a locals list, but
* it gets the job done.</p>
- *
- * @param orig null-ok; the original spec
- * @return null-ok; an appropriately modified spec, or the
+ *
+ * @param orig {@code null-ok;} the original spec
+ * @return {@code null-ok;} an appropriately modified spec, or the
* original if nothing needs to be done
*/
private static RegisterSpec filterSpec(RegisterSpec orig) {
@@ -814,9 +842,9 @@
* Adds an entry to the result, updating the adjunct tables
* accordingly.
*
- * @param address >= 0; the address
- * @param disposition non-null; the disposition
- * @param spec non-null; spec representing the local
+ * @param address {@code >= 0;} the address
+ * @param disposition {@code non-null;} the disposition
+ * @param spec {@code non-null;} spec representing the local
*/
private void add(int address, Disposition disposition,
RegisterSpec spec) {
@@ -834,11 +862,13 @@
}
/**
- * Adds or updates an end local (changing its disposition).
- *
- * @param address >= 0; the address
- * @param disposition non-null; the disposition
- * @param spec non-null; spec representing the local
+ * Adds or updates an end local (changing its disposition). If
+ * this would cause an empty range for a local, this instead
+ * removes the local entirely.
+ *
+ * @param address {@code >= 0;} the address
+ * @param disposition {@code non-null;} the disposition
+ * @param spec {@code non-null;} spec representing the local
*/
private void addOrUpdateEnd(int address, Disposition disposition,
RegisterSpec spec) {
@@ -850,29 +880,34 @@
int endAt = endIndices[regNum];
if (endAt >= 0) {
+ // There is a previous end.
Entry endEntry = result.get(endAt);
if ((endEntry.getAddress() == address) &&
endEntry.getRegisterSpec().equals(spec)) {
+ /*
+ * The end is for the right address and variable, so
+ * update it.
+ */
result.set(endAt, endEntry.withDisposition(disposition));
- regs.remove(spec);
+ regs.remove(spec); // TODO: Is this line superfluous?
return;
}
}
-
- add(address, disposition, spec);
+
+ endLocal(address, spec, disposition);
}
/**
* Finishes processing altogether and gets the result.
- *
- * @return non-null; the result list
+ *
+ * @return {@code non-null;} the result list
*/
public LocalList finish() {
aboutToProcess(Integer.MAX_VALUE, 0);
int resultSz = result.size();
int finalSz = resultSz - nullResultCount;
-
+
if (finalSz == 0) {
return EMPTY;
}
@@ -909,5 +944,5 @@
resultList.setImmutable();
return resultList;
}
- }
+ }
}
diff --git a/dx/src/com/android/dx/dex/code/LocalSnapshot.java b/dx/src/com/android/dx/dex/code/LocalSnapshot.java
index 19a9baa..409ad15 100644
--- a/dx/src/com/android/dx/dex/code/LocalSnapshot.java
+++ b/dx/src/com/android/dx/dex/code/LocalSnapshot.java
@@ -27,15 +27,15 @@
* the instance in an instruction array.
*/
public final class LocalSnapshot extends ZeroSizeInsn {
- /** non-null; local state associated with this instance */
+ /** {@code non-null;} local state associated with this instance */
private final RegisterSpecSet locals;
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param locals non-null; associated local variable state
+ * @param position {@code non-null;} source position
+ * @param locals {@code non-null;} associated local variable state
*/
public LocalSnapshot(SourcePosition position, RegisterSpecSet locals) {
super(position);
@@ -62,7 +62,7 @@
/**
* Gets the local state associated with this instance.
*
- * @return non-null; the state
+ * @return {@code non-null;} the state
*/
public RegisterSpecSet getLocals() {
return locals;
diff --git a/dx/src/com/android/dx/dex/code/LocalStart.java b/dx/src/com/android/dx/dex/code/LocalStart.java
index 22e20f8..ec70e30 100644
--- a/dx/src/com/android/dx/dex/code/LocalStart.java
+++ b/dx/src/com/android/dx/dex/code/LocalStart.java
@@ -28,7 +28,7 @@
*/
public final class LocalStart extends ZeroSizeInsn {
/**
- * non-null; register spec representing the local variable introduced
+ * {@code non-null;} register spec representing the local variable introduced
* by this instance
*/
private final RegisterSpec local;
@@ -36,8 +36,8 @@
/**
* Returns the local variable listing string for a single register spec.
*
- * @param spec non-null; the spec to convert
- * @return non-null; the string form
+ * @param spec {@code non-null;} the spec to convert
+ * @return {@code non-null;} the string form
*/
public static String localString(RegisterSpec spec) {
return spec.regString() + ' ' + spec.getLocalItem().toString() + ": " +
@@ -46,10 +46,10 @@
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param local non-null; register spec representing the local
+ * @param position {@code non-null;} source position
+ * @param local {@code non-null;} register spec representing the local
* variable introduced by this instance
*/
public LocalStart(SourcePosition position, RegisterSpec local) {
@@ -78,7 +78,7 @@
* Gets the register spec representing the local variable introduced
* by this instance.
*
- * @return non-null; the register spec
+ * @return {@code non-null;} the register spec
*/
public RegisterSpec getLocal() {
return local;
diff --git a/dx/src/com/android/dx/dex/code/OddSpacer.java b/dx/src/com/android/dx/dex/code/OddSpacer.java
index f99df36..727def0 100644
--- a/dx/src/com/android/dx/dex/code/OddSpacer.java
+++ b/dx/src/com/android/dx/dex/code/OddSpacer.java
@@ -21,7 +21,7 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Pseudo-instruction which either turns into a <code>nop</code> or
+ * Pseudo-instruction which either turns into a {@code nop} or
* nothingness, in order to make the subsequent instruction have an
* even address. This is used to align (subsequent) instructions that
* require it.
@@ -29,9 +29,9 @@
public final class OddSpacer extends VariableSizeInsn {
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
+ * @param position {@code non-null;} source position
*/
public OddSpacer(SourcePosition position) {
super(position, RegisterSpecList.EMPTY);
diff --git a/dx/src/com/android/dx/dex/code/OutputCollector.java b/dx/src/com/android/dx/dex/code/OutputCollector.java
index 98d8a9c..2643373 100644
--- a/dx/src/com/android/dx/dex/code/OutputCollector.java
+++ b/dx/src/com/android/dx/dex/code/OutputCollector.java
@@ -28,13 +28,13 @@
*/
public final class OutputCollector {
/**
- * non-null; the associated finisher (which holds the instruction
+ * {@code non-null;} the associated finisher (which holds the instruction
* list in-progress)
*/
private final OutputFinisher finisher;
/**
- * null-ok; suffix for the output, or <code>null</code> if the suffix
+ * {@code null-ok;} suffix for the output, or {@code null} if the suffix
* has been appended to the main output (by {@link #appendSuffixToOutput})
*/
private ArrayList<DalvInsn> suffix;
@@ -42,10 +42,10 @@
/**
* Constructs an instance.
*
- * @param initialCapacity >= 0; initial capacity of the output list
- * @param suffixInitialCapacity >= 0; initial capacity of the output
+ * @param initialCapacity {@code >= 0;} initial capacity of the output list
+ * @param suffixInitialCapacity {@code >= 0;} initial capacity of the output
* suffix
- * @param regCount >= 0; register count for the method
+ * @param regCount {@code >= 0;} register count for the method
*/
public OutputCollector(int initialCapacity, int suffixInitialCapacity,
int regCount) {
@@ -56,7 +56,7 @@
/**
* Adds an instruction to the output.
*
- * @param insn non-null; the instruction to add
+ * @param insn {@code non-null;} the instruction to add
*/
public void add(DalvInsn insn) {
finisher.add(insn);
@@ -68,9 +68,9 @@
* indicated instruction really is a reversible branch.
*
* @param which how many instructions back to find the branch;
- * <code>0</code> is the most recently added instruction,
- * <code>1</code> is the instruction before that, etc.
- * @param newTarget non-null; the new target for the reversed branch
+ * {@code 0} is the most recently added instruction,
+ * {@code 1} is the instruction before that, etc.
+ * @param newTarget {@code non-null;} the new target for the reversed branch
*/
public void reverseBranch(int which, CodeAddress newTarget) {
finisher.reverseBranch(which, newTarget);
@@ -79,7 +79,7 @@
/**
* Adds an instruction to the output suffix.
*
- * @param insn non-null; the instruction to add
+ * @param insn {@code non-null;} the instruction to add
*/
public void addSuffix(DalvInsn insn) {
suffix.add(insn);
@@ -89,7 +89,7 @@
* Gets the results of all the calls on this instance, in the form of
* an {@link OutputFinisher}.
*
- * @return non-null; the output finisher
+ * @return {@code non-null;} the output finisher
* @throws UnsupportedOperationException if this method has
* already been called
*/
diff --git a/dx/src/com/android/dx/dex/code/OutputFinisher.java b/dx/src/com/android/dx/dex/code/OutputFinisher.java
index 73eecf8..5b1d533 100644
--- a/dx/src/com/android/dx/dex/code/OutputFinisher.java
+++ b/dx/src/com/android/dx/dex/code/OutputFinisher.java
@@ -37,12 +37,12 @@
*/
public final class OutputFinisher {
/**
- * >= 0; register count for the method, not including any extra
+ * {@code >= 0;} register count for the method, not including any extra
* "reserved" registers needed to translate "difficult" instructions
*/
private final int unreservedRegCount;
- /** non-null; the list of instructions, per se */
+ /** {@code non-null;} the list of instructions, per se */
private ArrayList<DalvInsn> insns;
/** whether any instruction has position info */
@@ -52,7 +52,7 @@
private boolean hasAnyLocalInfo;
/**
- * >= 0; the count of reserved registers (low-numbered
+ * {@code >= 0;} the count of reserved registers (low-numbered
* registers used when expanding instructions that can't be
* represented simply); becomes valid after a call to {@link
* #massageInstructions}
@@ -62,8 +62,8 @@
/**
* Constructs an instance. It initially contains no instructions.
*
- * @param regCount >= 0; register count for the method
- * @param initialCapacity >= 0; initial capacity of the instructions
+ * @param regCount {@code >= 0;} register count for the method
+ * @param initialCapacity {@code >= 0;} initial capacity of the instructions
* list
*/
public OutputFinisher(int initialCapacity, int regCount) {
@@ -98,8 +98,8 @@
* Helper for {@link #add} which scrutinizes a single
* instruction for local variable information.
*
- * @param insn non-null; instruction to scrutinize
- * @return <code>true</code> iff the instruction refers to any
+ * @param insn {@code non-null;} instruction to scrutinize
+ * @return {@code true} iff the instruction refers to any
* named locals
*/
private static boolean hasLocalInfo(DalvInsn insn) {
@@ -125,8 +125,8 @@
* Helper for {@link #hasAnyLocalInfo} which scrutinizes a single
* register spec.
*
- * @param spec non-null; spec to scrutinize
- * @return <code>true</code> iff the spec refers to any
+ * @param spec {@code non-null;} spec to scrutinize
+ * @return {@code true} iff the spec refers to any
* named locals
*/
private static boolean hasLocalInfo(RegisterSpec spec) {
@@ -138,7 +138,7 @@
* Returns the set of all constants referred to by instructions added
* to this instance.
*
- * @return non-null; the set of constants
+ * @return {@code non-null;} the set of constants
*/
public HashSet<Constant> getAllConstants() {
HashSet<Constant> result = new HashSet<Constant>(20);
@@ -154,8 +154,8 @@
* Helper for {@link #getAllConstants} which adds all the info for
* a single instruction.
*
- * @param result non-null; result set to add to
- * @param insn non-null; instruction to scrutinize
+ * @param result {@code non-null;} result set to add to
+ * @param insn {@code non-null;} instruction to scrutinize
*/
private static void addConstants(HashSet<Constant> result,
DalvInsn insn) {
@@ -176,10 +176,10 @@
/**
* Helper for {@link #getAllConstants} which adds all the info for
- * a single <code>RegisterSpec</code>.
+ * a single {@code RegisterSpec}.
*
- * @param result non-null; result set to add to
- * @param spec null-ok; register spec to add
+ * @param result {@code non-null;} result set to add to
+ * @param spec {@code null-ok;} register spec to add
*/
private static void addConstants(HashSet<Constant> result,
RegisterSpec spec) {
@@ -208,7 +208,7 @@
/**
* Adds an instruction to the output.
*
- * @param insn non-null; the instruction to add
+ * @param insn {@code non-null;} the instruction to add
*/
public void add(DalvInsn insn) {
insns.add(insn);
@@ -218,8 +218,8 @@
/**
* Inserts an instruction in the output at the given offset.
*
- * @param at >= 0; what index to insert at
- * @param insn non-null; the instruction to insert
+ * @param at {@code >= 0;} what index to insert at
+ * @param insn {@code non-null;} the instruction to insert
*/
public void insert(int at, DalvInsn insn) {
insns.add(at, insn);
@@ -230,7 +230,7 @@
* Helper for {@link #add} and {@link #insert},
* which updates the position and local info flags.
*
- * @param insn non-null; an instruction that was just introduced
+ * @param insn {@code non-null;} an instruction that was just introduced
*/
private void updateInfo(DalvInsn insn) {
if (! hasAnyPositionInfo) {
@@ -253,9 +253,9 @@
* indicated instruction really is a reversible branch.
*
* @param which how many instructions back to find the branch;
- * <code>0</code> is the most recently added instruction,
- * <code>1</code> is the instruction before that, etc.
- * @param newTarget non-null; the new target for the reversed branch
+ * {@code 0} is the most recently added instruction,
+ * {@code 1} is the instruction before that, etc.
+ * @param newTarget {@code non-null;} the new target for the reversed branch
*/
public void reverseBranch(int which, CodeAddress newTarget) {
int size = insns.size();
@@ -284,7 +284,7 @@
* given callback to perform lookups. This should be called before
* calling {@link #finishProcessingAndGetList}.
*
- * @param callback non-null; callback object
+ * @param callback {@code non-null;} callback object
*/
public void assignIndices(DalvCode.AssignIndicesCallback callback) {
for (DalvInsn insn : insns) {
@@ -298,8 +298,8 @@
* Helper for {@link #assignIndices} which does assignment for one
* instruction.
*
- * @param insn non-null; the instruction
- * @param callback non-null; the callback
+ * @param insn {@code non-null;} the instruction
+ * @param callback {@code non-null;} the callback
*/
private static void assignIndices(CstInsn insn,
DalvCode.AssignIndicesCallback callback) {
@@ -336,7 +336,7 @@
* <p><b>Note:</b> This method may only be called once per instance
* of this class.</p>
*
- * @return non-null; the output list
+ * @return {@code non-null;} the output list
* @throws UnsupportedOperationException if this method has
* already been called
*/
@@ -359,7 +359,7 @@
* the format out of each instruction into a separate array, to be
* further manipulated as things progress.
*
- * @return non-null; the array of formats
+ * @return {@code non-null;} the array of formats
*/
private InsnFormat[] makeFormatsArray() {
int size = insns.size();
@@ -375,11 +375,11 @@
/**
* Helper for {@link #finishProcessingAndGetList}, which figures
* out how many reserved registers are required and then reserving
- * them. It also updates the given <code>formats</code> array so
+ * them. It also updates the given {@code formats} array so
* as to avoid extra work when constructing the massaged
* instruction list.
*
- * @param formats non-null; array of per-instruction format selections
+ * @param formats {@code non-null;} array of per-instruction format selections
*/
private void reserveRegisters(InsnFormat[] formats) {
int oldReservedCount = (reservedCount < 0) ? 0 : reservedCount;
@@ -425,11 +425,11 @@
* Helper for {@link #reserveRegisters}, which does one
* pass over the instructions, calculating the number of
* registers that need to be reserved. It also updates the
- * <code>formats</code> list to help avoid extra work in future
+ * {@code formats} list to help avoid extra work in future
* register reservation passes.
*
- * @param formats non-null; array of per-instruction format selections
- * @return >= 0; the count of reserved registers
+ * @param formats {@code non-null;} array of per-instruction format selections
+ * @return {@code >= 0;} the count of reserved registers
*/
private int calculateReservedCount(InsnFormat[] formats) {
int size = insns.size();
@@ -470,16 +470,16 @@
/**
* Attempts to fit the given instruction into a format, returning
- * either a format that the instruction fits into or <code>null</code>
+ * either a format that the instruction fits into or {@code null}
* to indicate that the instruction will need to be expanded. This
* fitting process starts with the given format as a first "best
* guess" and then pessimizes from there if necessary.
*
- * @param insn non-null; the instruction in question
- * @param format null-ok; the current guess as to the best instruction
- * format to use; <code>null</code> means that no simple format fits
- * @return null-ok; a possibly-different format, which is either a
- * good fit or <code>null</code> to indicate that no simple format
+ * @param insn {@code non-null;} the instruction in question
+ * @param format {@code null-ok;} the current guess as to the best instruction
+ * format to use; {@code null} means that no simple format fits
+ * @return {@code null-ok;} a possibly-different format, which is either a
+ * good fit or {@code null} to indicate that no simple format
* fits
*/
private InsnFormat findFormatForInsn(DalvInsn insn, InsnFormat format) {
@@ -527,7 +527,7 @@
* final addresses aren't known at the point that this method is
* called.</p>
*
- * @param formats non-null; array of per-instruction format selections
+ * @param formats {@code non-null;} array of per-instruction format selections
*/
private void massageInstructions(InsnFormat[] formats) {
if (reservedCount == 0) {
@@ -566,8 +566,8 @@
* problems) is expanded into a series of instances that together
* perform the proper function.
*
- * @param formats non-null; array of per-instruction format selections
- * @return non-null; the replacement list
+ * @param formats {@code non-null;} array of per-instruction format selections
+ * @return {@code non-null;} the replacement list
*/
private ArrayList<DalvInsn> performExpansion(InsnFormat[] formats) {
int size = insns.size();
@@ -651,9 +651,9 @@
* Helper for {@link #assignAddressesAndFixBranches}, which checks
* the branch target size requirement of each branch instruction
* to make sure it fits. For instructions that don't fit, this
- * rewrites them to use a <code>goto</code> of some sort. In the
+ * rewrites them to use a {@code goto} of some sort. In the
* case of a conditional branch that doesn't fit, the sense of the
- * test is reversed in order to branch around a <code>goto</code>
+ * test is reversed in order to branch around a {@code goto}
* to the original target.
*
* @return whether any branches had to be fixed
diff --git a/dx/src/com/android/dx/dex/code/PositionList.java b/dx/src/com/android/dx/dex/code/PositionList.java
index d8f76eb..41e3667 100644
--- a/dx/src/com/android/dx/dex/code/PositionList.java
+++ b/dx/src/com/android/dx/dex/code/PositionList.java
@@ -24,7 +24,7 @@
* method to extract an instance out of a {@link DalvInsnList}.
*/
public final class PositionList extends FixedSizeList {
- /** non-null; empty instance */
+ /** {@code non-null;} empty instance */
public static final PositionList EMPTY = new PositionList(0);
/**
@@ -50,10 +50,10 @@
* Extracts and returns the source position information out of an
* instruction list.
*
- * @param insns non-null; instructions to convert
+ * @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
- * @return non-null; the positions list
+ * @return {@code non-null;} the positions list
*/
public static PositionList make(DalvInsnList insns, int howMuch) {
switch (howMuch) {
@@ -112,9 +112,9 @@
}
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
- * @param size >= 0; the size of the list
+ * @param size {@code >= 0;} the size of the list
*/
public PositionList(int size) {
super(size);
@@ -123,10 +123,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Entry get(int n) {
return (Entry) get0(n);
@@ -135,8 +135,8 @@
/**
* Sets the entry at the given index.
*
- * @param n >= 0, < size(); which index
- * @param entry non-null; the entry to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param entry {@code non-null;} the entry to set at {@code n}
*/
public void set(int n, Entry entry) {
set0(n, entry);
@@ -146,17 +146,17 @@
* Entry in a position list.
*/
public static class Entry {
- /** >= 0; address of this entry */
+ /** {@code >= 0;} address of this entry */
private final int address;
- /** non-null; corresponding source position information */
+ /** {@code non-null;} corresponding source position information */
private final SourcePosition position;
/**
* Constructs an instance.
*
- * @param address >= 0; address of this entry
- * @param position non-null; corresponding source position information
+ * @param address {@code >= 0;} address of this entry
+ * @param position {@code non-null;} corresponding source position information
*/
public Entry (int address, SourcePosition position) {
if (address < 0) {
@@ -174,7 +174,7 @@
/**
* Gets the address.
*
- * @return >= 0; the address
+ * @return {@code >= 0;} the address
*/
public int getAddress() {
return address;
@@ -183,7 +183,7 @@
/**
* Gets the source position information.
*
- * @return non-null; the position information
+ * @return {@code non-null;} the position information
*/
public SourcePosition getPosition() {
return position;
diff --git a/dx/src/com/android/dx/dex/code/RopToDop.java b/dx/src/com/android/dx/dex/code/RopToDop.java
index 8ad0e64..0385467 100644
--- a/dx/src/com/android/dx/dex/code/RopToDop.java
+++ b/dx/src/com/android/dx/dex/code/RopToDop.java
@@ -35,7 +35,7 @@
* {@link Dop} instances.
*/
public final class RopToDop {
- /** non-null; map from all the common rops to dalvik opcodes */
+ /** {@code non-null;} map from all the common rops to dalvik opcodes */
private static final HashMap<Rop, Dop> MAP;
/**
@@ -278,7 +278,7 @@
* Returns the dalvik opcode appropriate for the given register-based
* instruction.
*
- * @param insn non-null; the original instruction
+ * @param insn {@code non-null;} the original instruction
* @return the corresponding dalvik opcode; one of the constants in
* {@link Dops}
*/
diff --git a/dx/src/com/android/dx/dex/code/RopTranslator.java b/dx/src/com/android/dx/dex/code/RopTranslator.java
index f3dfe0b..9f47b13 100644
--- a/dx/src/com/android/dx/dex/code/RopTranslator.java
+++ b/dx/src/com/android/dx/dex/code/RopTranslator.java
@@ -46,7 +46,7 @@
* #translate} method is the thing to call on this class.
*/
public final class RopTranslator {
- /** non-null; method to translate */
+ /** {@code non-null;} method to translate */
private final RopMethod method;
/**
@@ -55,22 +55,22 @@
*/
private final int positionInfo;
- /** null-ok; local variable info to use */
+ /** {@code null-ok;} local variable info to use */
private final LocalVariableInfo locals;
- /** non-null; container for all the address objects for the method */
+ /** {@code non-null;} container for all the address objects for the method */
private final BlockAddresses addresses;
- /** non-null; list of output instructions in-progress */
+ /** {@code non-null;} list of output instructions in-progress */
private final OutputCollector output;
- /** non-null; visitor to use during translation */
+ /** {@code non-null;} visitor to use during translation */
private final TranslationVisitor translationVisitor;
- /** >= 0; register count for the method */
+ /** {@code >= 0;} register count for the method */
private final int regCount;
- /** null-ok; block output order; becomes non-null in {@link #pickOrder} */
+ /** {@code null-ok;} block output order; becomes non-null in {@link #pickOrder} */
private int[] order;
/** size, in register units, of all the parameters to this method */
@@ -86,13 +86,13 @@
* Translates a {@link RopMethod}. This may modify the given
* input.
*
- * @param method non-null; the original method
+ * @param method {@code non-null;} the original method
* @param positionInfo how much position info to preserve; one of the
* static constants in {@link PositionList}
- * @param locals null-ok; local variable information to use
+ * @param locals {@code null-ok;} local variable information to use
* @param paramSize size, in register units, of all the parameters to
* this method
- * @return non-null; the translated version
+ * @return {@code non-null;} the translated version
*/
public static DalvCode translate(RopMethod method, int positionInfo,
LocalVariableInfo locals, int paramSize) {
@@ -105,10 +105,10 @@
/**
* Constructs an instance. This method is private. Use {@link #translate}.
*
- * @param method non-null; the original method
+ * @param method {@code non-null;} the original method
* @param positionInfo how much position info to preserve; one of the
* static constants in {@link PositionList}
- * @param locals null-ok; local variable information to use
+ * @param locals {@code null-ok;} local variable information to use
* @param paramSize size, in register units, of all the parameters to
* this method
*/
@@ -177,7 +177,7 @@
/*
* We almost could just check the first block here, but the
- * <code>cf</code> layer will put in a second move-param in a
+ * {@code cf} layer will put in a second move-param in a
* subsequent block in the case of synchronized methods.
*/
method.getBlocks().forEachInsn(new Insn.BaseVisitor() {
@@ -199,7 +199,7 @@
/**
* Does the translation and returns the result.
*
- * @return non-null; the result
+ * @return {@code non-null;} the result
*/
private DalvCode translateAndGetResult() {
pickOrder();
@@ -232,9 +232,9 @@
* Helper for {@link #outputInstructions}, which does the processing
* and output of one block.
*
- * @param block non-null; the block to process and output
- * @param nextLabel >= -1; the next block that will be processed, or
- * <code>-1</code> if there is no next 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
*/
private void outputBlock(BasicBlock block, int nextLabel) {
// Append the code address for this block.
@@ -440,8 +440,8 @@
* two register sources, and have a source equal to the result,
* place that source first.
*
- * @param insn non-null; instruction in question
- * @return non-null; the instruction's complete register list
+ * @param insn {@code non-null;} instruction in question
+ * @return {@code non-null;} the instruction's complete register list
*/
private static RegisterSpecList getRegs(Insn insn) {
return getRegs(insn, insn.getResult());
@@ -453,9 +453,9 @@
* two register sources, and have a source equal to the result,
* place that source first.
*
- * @param insn non-null; instruction in question
- * @param resultReg null-ok; the real result to use (ignore the insn's)
- * @return non-null; the instruction's complete register list
+ * @param insn {@code non-null;} instruction in question
+ * @param resultReg {@code null-ok;} the real result to use (ignore the insn's)
+ * @return {@code non-null;} the instruction's complete register list
*/
private static RegisterSpecList getRegs(Insn insn,
RegisterSpec resultReg) {
@@ -486,14 +486,14 @@
* Instruction visitor class for doing the instruction translation per se.
*/
private class TranslationVisitor implements Insn.Visitor {
- /** non-null; list of output instructions in-progress */
+ /** {@code non-null;} list of output instructions in-progress */
private final OutputCollector output;
- /** non-null; basic block being worked on */
+ /** {@code non-null;} basic block being worked on */
private BasicBlock block;
/**
- * null-ok; code address for the salient last instruction of the
+ * {@code null-ok;} code address for the salient last instruction of the
* block (used before switches and throwing instructions)
*/
private CodeAddress lastAddress;
@@ -501,7 +501,7 @@
/**
* Constructs an instance.
*
- * @param output non-null; destination for instruction output
+ * @param output {@code non-null;} destination for instruction output
*/
public TranslationVisitor(OutputCollector output) {
this.output = output;
@@ -510,8 +510,8 @@
/**
* Sets the block currently being worked on.
*
- * @param block non-null; the block
- * @param lastAddress non-null; code address for the salient
+ * @param block {@code non-null;} the block
+ * @param lastAddress {@code non-null;} code address for the salient
* last instruction of the block
*/
public void setBlock(BasicBlock block, CodeAddress lastAddress) {
@@ -654,7 +654,7 @@
* the RegisterSpec of the result of the move-result-pseudo at the
* top of that block or null if none.
*
- * @return null-ok; result of move-result-pseudo at the beginning of
+ * @return {@code null-ok;} result of move-result-pseudo at the beginning of
* primary successor
*/
private RegisterSpec getNextMoveResultPseudo()
@@ -783,7 +783,7 @@
/**
* Adds to the output.
*
- * @param insn non-null; instruction to add
+ * @param insn {@code non-null;} instruction to add
*/
protected void addOutput(DalvInsn insn) {
output.add(insn);
@@ -792,7 +792,7 @@
/**
* Adds to the output suffix.
*
- * @param insn non-null; instruction to add
+ * @param insn {@code non-null;} instruction to add
*/
protected void addOutputSuffix(DalvInsn insn) {
output.addSuffix(insn);
@@ -805,14 +805,14 @@
*/
private class LocalVariableAwareTranslationVisitor
extends TranslationVisitor {
- /** non-null; local variable info */
+ /** {@code non-null;} local variable info */
private LocalVariableInfo locals;
/**
* Constructs an instance.
*
- * @param output non-null; destination for instruction output
- * @param locals non-null; the local variable info
+ * @param output {@code non-null;} destination for instruction output
+ * @param locals {@code non-null;} the local variable info
*/
public LocalVariableAwareTranslationVisitor(OutputCollector output,
LocalVariableInfo locals) {
@@ -859,7 +859,7 @@
* Adds a {@link LocalStart} to the output if the given
* instruction in fact introduces a local variable.
*
- * @param insn non-null; instruction in question
+ * @param insn {@code non-null;} instruction in question
*/
public void addIntroductionIfNecessary(Insn insn) {
RegisterSpec spec = locals.getAssignment(insn);
diff --git a/dx/src/com/android/dx/dex/code/SimpleInsn.java b/dx/src/com/android/dx/dex/code/SimpleInsn.java
index ba20409..5e7b259 100644
--- a/dx/src/com/android/dx/dex/code/SimpleInsn.java
+++ b/dx/src/com/android/dx/dex/code/SimpleInsn.java
@@ -26,11 +26,11 @@
public final class SimpleInsn extends FixedSizeInsn {
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
* @param opcode the opcode; one of the constants from {@link Dops}
- * @param position non-null; source position
- * @param registers non-null; register list, including a
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
* result register if appropriate (that is, registers may be either
* ins or outs)
*/
diff --git a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
index 1240f3f..6e3a169 100644
--- a/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
+++ b/dx/src/com/android/dx/dex/code/StdCatchBuilder.java
@@ -35,22 +35,22 @@
/** the maximum range of a single catch handler, in code units */
private static final int MAX_CATCH_RANGE = 65535;
- /** non-null; method to build the list for */
+ /** {@code non-null;} method to build the list for */
private final RopMethod method;
- /** non-null; block output order */
+ /** {@code non-null;} block output order */
private final int[] order;
- /** non-null; address objects for each block */
+ /** {@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 non-null; method to build the list for
- * @param order non-null; block output order
- * @param addresses non-null; address objects for each block
+ * @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
*/
public StdCatchBuilder(RopMethod method, int[] order,
BlockAddresses addresses) {
@@ -78,7 +78,6 @@
/** {@inheritDoc} */
public boolean hasAnyCatches() {
- HashSet<Type> result = new HashSet<Type>(20);
BasicBlockList blocks = method.getBlocks();
int size = blocks.size();
@@ -115,10 +114,10 @@
/**
* Builds and returns the catch table for a given method.
*
- * @param method non-null; method to build the list for
- * @param order non-null; block output order
- * @param addresses non-null; address objects for each block
- * @return non-null; the constructed table
+ * @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
+ * @return {@code non-null;} the constructed table
*/
public static CatchTable build(RopMethod method, int[] order,
BlockAddresses addresses) {
@@ -210,9 +209,9 @@
/**
* Makes the {@link CatchHandlerList} for the given basic block.
*
- * @param block non-null; block to get entries for
- * @param addresses non-null; address objects for each block
- * @return non-null; array of entries
+ * @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
*/
private static CatchHandlerList handlersFor(BasicBlock block,
BlockAddresses addresses) {
@@ -267,10 +266,10 @@
* Makes a {@link CatchTable#Entry} for the given block range and
* handlers.
*
- * @param start non-null; the start block for the range (inclusive)
- * @param end non-null; the start block for the range (also inclusive)
- * @param handlers non-null; the handlers for the range
- * @param addresses non-null; address objects for each block
+ * @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 handlers {@code non-null;} the handlers for the range
+ * @param addresses {@code non-null;} address objects for each block
*/
private static CatchTable.Entry makeEntry(BasicBlock start,
BasicBlock end, CatchHandlerList handlers,
@@ -293,10 +292,10 @@
* for a catch handler. This is true as long as the covered range is
* under 65536 code units.
*
- * @param start non-null; the start block for the range (inclusive)
- * @param end non-null; the start block for the range (also inclusive)
- * @param addresses non-null; address objects for each block
- * @return <code>true</code> if the range is valid as a catch range
+ * @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
+ * @return {@code true} if the range is valid as a catch range
*/
private static boolean rangeIsValid(BasicBlock start, BasicBlock end,
BlockAddresses addresses) {
diff --git a/dx/src/com/android/dx/dex/code/SwitchData.java b/dx/src/com/android/dx/dex/code/SwitchData.java
index 1aaafa9..e5a8da4 100644
--- a/dx/src/com/android/dx/dex/code/SwitchData.java
+++ b/dx/src/com/android/dx/dex/code/SwitchData.java
@@ -29,16 +29,16 @@
*/
public final class SwitchData extends VariableSizeInsn {
/**
- * non-null; address representing the instruction that uses this
+ * {@code non-null;} address representing the instruction that uses this
* instance
*/
private final CodeAddress user;
- /** non-null; sorted list of switch cases (keys) */
+ /** {@code non-null;} sorted list of switch cases (keys) */
private final IntList cases;
/**
- * non-null; corresponding list of code addresses; the branch
+ * {@code non-null;} corresponding list of code addresses; the branch
* target for each case
*/
private final CodeAddress[] targets;
@@ -48,13 +48,13 @@
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param user non-null; address representing the instruction that
+ * @param position {@code non-null;} source position
+ * @param user {@code non-null;} address representing the instruction that
* uses this instance
- * @param cases non-null; sorted list of switch cases (keys)
- * @param targets non-null; corresponding list of code addresses; the
+ * @param cases {@code non-null;} sorted list of switch cases (keys)
+ * @param targets {@code non-null;} corresponding list of code addresses; the
* branch target for each case
*/
public SwitchData(SourcePosition position, CodeAddress user,
@@ -151,7 +151,7 @@
/**
* Returns whether or not this instance's data will be output as packed.
*
- * @return <code>true</code> iff the data is to be packed
+ * @return {@code true} iff the data is to be packed
*/
public boolean isPacked() {
return packed;
@@ -202,8 +202,8 @@
* Gets the size of a packed table for the given cases, in 16-bit code
* units.
*
- * @param cases non-null; sorted list of cases
- * @return >= -1; the packed table size or <code>-1</code> if the
+ * @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
*/
private static long packedCodeSize(IntList cases) {
@@ -219,8 +219,8 @@
* Gets the size of a sparse table for the given cases, in 16-bit code
* units.
*
- * @param cases non-null; sorted list of cases
- * @return > 0; the sparse table size
+ * @param cases {@code non-null;} sorted list of cases
+ * @return {@code > 0;} the sparse table size
*/
private static long sparseCodeSize(IntList cases) {
int sz = cases.size();
@@ -231,8 +231,8 @@
/**
* Determines whether the given list of cases warrant being packed.
*
- * @param cases non-null; sorted list of cases
- * @return <code>true</code> iff the table encoding the cases
+ * @param cases {@code non-null;} sorted list of cases
+ * @return {@code true} iff the table encoding the cases
* should be packed
*/
private static boolean shouldPack(IntList cases) {
diff --git a/dx/src/com/android/dx/dex/code/TargetInsn.java b/dx/src/com/android/dx/dex/code/TargetInsn.java
index 5620795..0faaada 100644
--- a/dx/src/com/android/dx/dex/code/TargetInsn.java
+++ b/dx/src/com/android/dx/dex/code/TargetInsn.java
@@ -23,20 +23,20 @@
* Instruction which has a single branch target.
*/
public final class TargetInsn extends FixedSizeInsn {
- /** non-null; the branch target */
+ /** {@code non-null;} the branch target */
private CodeAddress target;
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>), and the target is initially
- * <code>null</code>.
+ * unknown ({@code -1}), and the target is initially
+ * {@code null}.
*
* @param opcode the opcode; one of the constants from {@link Dops}
- * @param position non-null; source position
- * @param registers non-null; register list, including a
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} register list, including a
* result register if appropriate (that is, registers may be either
* ins or outs)
- * @param target non-null; the branch target
+ * @param target {@code non-null;} the branch target
*/
public TargetInsn(Dop opcode, SourcePosition position,
RegisterSpecList registers, CodeAddress target) {
@@ -64,12 +64,12 @@
/**
* Returns an instance that is just like this one, except that its
* opcode has the opposite sense (as a test; e.g. a
- * <code>lt</code> test becomes a <code>ge</code>), and its branch
+ * {@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 non-null; the new branch target
- * @return non-null; an appropriately-constructed instance
+ * @param target {@code non-null;} the new branch target
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public TargetInsn withNewTargetAndReversed(CodeAddress target) {
Dop opcode = getOpcode().getOppositeTest();
@@ -80,7 +80,7 @@
/**
* Gets the unique branch target of this instruction.
*
- * @return non-null; the branch target
+ * @return {@code non-null;} the branch target
*/
public CodeAddress getTarget() {
return target;
@@ -90,9 +90,9 @@
* Gets the target address of this instruction. This is only valid
* to call if the target instruction has been assigned an address,
* and it is merely a convenient shorthand for
- * <code>getTarget().getAddress()</code>.
+ * {@code getTarget().getAddress()}.
*
- * @return >= 0; the target address
+ * @return {@code >= 0;} the target address
*/
public int getTargetAddress() {
return target.getAddress();
@@ -102,7 +102,7 @@
* Gets the branch offset of this instruction. This is only valid to
* 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()</code>.
+ * {@code getTargetAddress() - getAddress()}.
*
* @return the branch offset
*/
@@ -113,8 +113,8 @@
/**
* Returns whether the target offset is known.
*
- * @return <code>true</code> if the target offset is known or
- * <code>false</code> if not
+ * @return {@code true} if the target offset is known or
+ * {@code false} if not
*/
public boolean hasTargetOffset() {
return hasAddress() && target.hasAddress();
diff --git a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
index 7884249..889a50c 100644
--- a/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
+++ b/dx/src/com/android/dx/dex/code/VariableSizeInsn.java
@@ -25,10 +25,10 @@
public abstract class VariableSizeInsn extends DalvInsn {
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
- * @param registers non-null; source registers
+ * @param position {@code non-null;} source position
+ * @param registers {@code non-null;} source registers
*/
public VariableSizeInsn(SourcePosition position,
RegisterSpecList registers) {
diff --git a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
index 2ddb181..198bebf 100644
--- a/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
+++ b/dx/src/com/android/dx/dex/code/ZeroSizeInsn.java
@@ -28,9 +28,9 @@
public abstract class ZeroSizeInsn extends DalvInsn {
/**
* Constructs an instance. The output address of this instance is initially
- * unknown (<code>-1</code>).
+ * unknown ({@code -1}).
*
- * @param position non-null; source position
+ * @param position {@code non-null;} source position
*/
public ZeroSizeInsn(SourcePosition position) {
super(Dops.SPECIAL_FORMAT, position, RegisterSpecList.EMPTY);
diff --git a/dx/src/com/android/dx/dex/code/form/Form10t.java b/dx/src/com/android/dx/dex/code/form/Form10t.java
index 8551012..82b731d 100644
--- a/dx/src/com/android/dx/dex/code/form/Form10t.java
+++ b/dx/src/com/android/dx/dex/code/form/Form10t.java
@@ -22,11 +22,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>10t</code>. See the instruction format spec
+ * Instruction format {@code 10t}. See the instruction format spec
* for details.
*/
public final class Form10t extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form10t();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form10x.java b/dx/src/com/android/dx/dex/code/form/Form10x.java
index 7dc7c43..c7a22a6 100644
--- a/dx/src/com/android/dx/dex/code/form/Form10x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form10x.java
@@ -22,11 +22,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>10x</code>. See the instruction format spec
+ * Instruction format {@code 10x}. See the instruction format spec
* for details.
*/
public final class Form10x extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form10x();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form11n.java b/dx/src/com/android/dx/dex/code/form/Form11n.java
index b94038b..d63fc6f 100644
--- a/dx/src/com/android/dx/dex/code/form/Form11n.java
+++ b/dx/src/com/android/dx/dex/code/form/Form11n.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>11n</code>. See the instruction format spec
+ * Instruction format {@code 11n}. See the instruction format spec
* for details.
*/
public final class Form11n extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form11n();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form11x.java b/dx/src/com/android/dx/dex/code/form/Form11x.java
index d656147..b4acc1a 100644
--- a/dx/src/com/android/dx/dex/code/form/Form11x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form11x.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>11x</code>. See the instruction format spec
+ * Instruction format {@code 11x}. See the instruction format spec
* for details.
*/
public final class Form11x extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form11x();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form12x.java b/dx/src/com/android/dx/dex/code/form/Form12x.java
index 3ed8ce9..c7754be 100644
--- a/dx/src/com/android/dx/dex/code/form/Form12x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form12x.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>12x</code>. See the instruction format spec
+ * Instruction format {@code 12x}. See the instruction format spec
* for details.
*/
public final class Form12x extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form12x();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form20t.java b/dx/src/com/android/dx/dex/code/form/Form20t.java
index 341bef3..0b5a3b2 100644
--- a/dx/src/com/android/dx/dex/code/form/Form20t.java
+++ b/dx/src/com/android/dx/dex/code/form/Form20t.java
@@ -22,11 +22,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>20t</code>. See the instruction format spec
+ * Instruction format {@code 20t}. See the instruction format spec
* for details.
*/
public final class Form20t extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form20t();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form21c.java b/dx/src/com/android/dx/dex/code/form/Form21c.java
index 5695e7a..ed1ec3c 100644
--- a/dx/src/com/android/dx/dex/code/form/Form21c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form21c.java
@@ -28,11 +28,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>21c</code>. See the instruction format spec
+ * Instruction format {@code 21c}. See the instruction format spec
* for details.
*/
public final class Form21c extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form21c();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form21h.java b/dx/src/com/android/dx/dex/code/form/Form21h.java
index cf4b471..e0bd751 100644
--- a/dx/src/com/android/dx/dex/code/form/Form21h.java
+++ b/dx/src/com/android/dx/dex/code/form/Form21h.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>21h</code>. See the instruction format spec
+ * Instruction format {@code 21h}. See the instruction format spec
* for details.
*/
public final class Form21h extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form21h();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form21s.java b/dx/src/com/android/dx/dex/code/form/Form21s.java
index df10f80..a03ee43 100644
--- a/dx/src/com/android/dx/dex/code/form/Form21s.java
+++ b/dx/src/com/android/dx/dex/code/form/Form21s.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>21s</code>. See the instruction format spec
+ * Instruction format {@code 21s}. See the instruction format spec
* for details.
*/
public final class Form21s extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form21s();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form21t.java b/dx/src/com/android/dx/dex/code/form/Form21t.java
index 03f2ddf..f0ce644 100644
--- a/dx/src/com/android/dx/dex/code/form/Form21t.java
+++ b/dx/src/com/android/dx/dex/code/form/Form21t.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>21t</code>. See the instruction format spec
+ * Instruction format {@code 21t}. See the instruction format spec
* for details.
*/
public final class Form21t extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form21t();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form22b.java b/dx/src/com/android/dx/dex/code/form/Form22b.java
index e2a777f..2884fbb 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22b.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22b.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>22b</code>. See the instruction format spec
+ * Instruction format {@code 22b}. See the instruction format spec
* for details.
*/
public final class Form22b extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form22b();
/**
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 547eea8..e77677f 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22c.java
@@ -27,11 +27,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>22c</code>. See the instruction format spec
+ * Instruction format {@code 22c}. See the instruction format spec
* for details.
*/
public final class Form22c extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form22c();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form22s.java b/dx/src/com/android/dx/dex/code/form/Form22s.java
index 3ed173f..5964217 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22s.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22s.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>22s</code>. See the instruction format spec
+ * Instruction format {@code 22s}. See the instruction format spec
* for details.
*/
public final class Form22s extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form22s();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form22t.java b/dx/src/com/android/dx/dex/code/form/Form22t.java
index 1034b92..1577803 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22t.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22t.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>22t</code>. See the instruction format spec
+ * Instruction format {@code 22t}. See the instruction format spec
* for details.
*/
public final class Form22t extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form22t();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form22x.java b/dx/src/com/android/dx/dex/code/form/Form22x.java
index ee91e85..b7ce4e7 100644
--- a/dx/src/com/android/dx/dex/code/form/Form22x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form22x.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>22x</code>. See the instruction format spec
+ * Instruction format {@code 22x}. See the instruction format spec
* for details.
*/
public final class Form22x extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form22x();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form23x.java b/dx/src/com/android/dx/dex/code/form/Form23x.java
index c0a4482..64dd6b0 100644
--- a/dx/src/com/android/dx/dex/code/form/Form23x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form23x.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>23x</code>. See the instruction format spec
+ * Instruction format {@code 23x}. See the instruction format spec
* for details.
*/
public final class Form23x extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form23x();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form30t.java b/dx/src/com/android/dx/dex/code/form/Form30t.java
index 32e2efa..af0a699 100644
--- a/dx/src/com/android/dx/dex/code/form/Form30t.java
+++ b/dx/src/com/android/dx/dex/code/form/Form30t.java
@@ -22,11 +22,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>30t</code>. See the instruction format spec
+ * Instruction format {@code 30t}. See the instruction format spec
* for details.
*/
public final class Form30t extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form30t();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form31c.java b/dx/src/com/android/dx/dex/code/form/Form31c.java
index 5837009..0c983c5 100644
--- a/dx/src/com/android/dx/dex/code/form/Form31c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form31c.java
@@ -28,11 +28,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>31c</code>. See the instruction format spec
+ * Instruction format {@code 31c}. See the instruction format spec
* for details.
*/
public final class Form31c extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form31c();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form31i.java b/dx/src/com/android/dx/dex/code/form/Form31i.java
index 2855bcb..c893a12 100644
--- a/dx/src/com/android/dx/dex/code/form/Form31i.java
+++ b/dx/src/com/android/dx/dex/code/form/Form31i.java
@@ -25,11 +25,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>31i</code>. See the instruction format spec
+ * Instruction format {@code 31i}. See the instruction format spec
* for details.
*/
public final class Form31i extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form31i();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form31t.java b/dx/src/com/android/dx/dex/code/form/Form31t.java
index 5472687..682408c 100644
--- a/dx/src/com/android/dx/dex/code/form/Form31t.java
+++ b/dx/src/com/android/dx/dex/code/form/Form31t.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>31t</code>. See the instruction format spec
+ * Instruction format {@code 31t}. See the instruction format spec
* for details.
*/
public final class Form31t extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form31t();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form32x.java b/dx/src/com/android/dx/dex/code/form/Form32x.java
index 9c52d93..4a981ee 100644
--- a/dx/src/com/android/dx/dex/code/form/Form32x.java
+++ b/dx/src/com/android/dx/dex/code/form/Form32x.java
@@ -23,11 +23,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>32x</code>. See the instruction format spec
+ * Instruction format {@code 32x}. See the instruction format spec
* for details.
*/
public final class Form32x extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form32x();
/**
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 6be55fc..411e3c3 100644
--- a/dx/src/com/android/dx/dex/code/form/Form35c.java
+++ b/dx/src/com/android/dx/dex/code/form/Form35c.java
@@ -28,11 +28,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>35c</code>. See the instruction format spec
+ * Instruction format {@code 35c}. See the instruction format spec
* for details.
*/
public final class Form35c extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form35c();
/** Maximal number of operands */
@@ -120,12 +120,12 @@
/**
* Gets the number of words required for the given register list, where
- * category-2 values count as two words. Return <code>-1</code> if the
+ * 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 non-null; the register list in question
- * @return >= -1; the number of words required, or <code>-1</code>
+ * @param regs {@code non-null;} the register list in question
+ * @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) {
@@ -161,8 +161,8 @@
* entries. This returns the original list if no modification is
* required
*
- * @param orig non-null; the original list
- * @return non-null; the list with the described transformation
+ * @param orig {@code non-null;} the original list
+ * @return {@code non-null;} the list with the described transformation
*/
private static RegisterSpecList explicitize(RegisterSpecList orig) {
int wordCount = wordCount(orig);
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 0accbc2..2d185cf 100644
--- a/dx/src/com/android/dx/dex/code/form/Form3rc.java
+++ b/dx/src/com/android/dx/dex/code/form/Form3rc.java
@@ -27,11 +27,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>3rc</code>. See the instruction format spec
+ * Instruction format {@code 3rc}. See the instruction format spec
* for details.
*/
public final class Form3rc extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form3rc();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/Form51l.java b/dx/src/com/android/dx/dex/code/form/Form51l.java
index 09a32f6..9e3ab6a 100644
--- a/dx/src/com/android/dx/dex/code/form/Form51l.java
+++ b/dx/src/com/android/dx/dex/code/form/Form51l.java
@@ -26,11 +26,11 @@
import com.android.dx.util.AnnotatedOutput;
/**
- * Instruction format <code>51l</code>. See the instruction format spec
+ * Instruction format {@code 51l}. See the instruction format spec
* for details.
*/
public final class Form51l extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new Form51l();
/**
diff --git a/dx/src/com/android/dx/dex/code/form/SpecialFormat.java b/dx/src/com/android/dx/dex/code/form/SpecialFormat.java
index 79efd67..8a2e5ed 100644
--- a/dx/src/com/android/dx/dex/code/form/SpecialFormat.java
+++ b/dx/src/com/android/dx/dex/code/form/SpecialFormat.java
@@ -27,10 +27,10 @@
* lists. Most of the overridden methods on this class end up throwing
* exceptions, as code should know (implicitly or explicitly) to avoid
* using this class. The one exception is {@link #isCompatible}, which
- * always returns <code>true</code>.
+ * always returns {@code true}.
*/
public final class SpecialFormat extends InsnFormat {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final InsnFormat THE_ONE = new SpecialFormat();
/**
diff --git a/dx/src/com/android/dx/dex/file/AnnotationItem.java b/dx/src/com/android/dx/dex/file/AnnotationItem.java
index 43ac362..08422bc 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationItem.java
@@ -46,20 +46,20 @@
/** the required alignment for instances of this class */
private static final int ALIGNMENT = 1;
- /** non-null; unique instance of {@link #TypeIdSorter} */
+ /** {@code non-null;} unique instance of {@link #TypeIdSorter} */
private static final TypeIdSorter TYPE_ID_SORTER = new TypeIdSorter();
- /** non-null; the annotation to represent */
+ /** {@code non-null;} the annotation to represent */
private final Annotation annotation;
/**
- * null-ok; type reference for the annotation type; set during
+ * {@code null-ok;} type reference for the annotation type; set during
* {@link #addContents}
*/
private TypeIdItem type;
/**
- * null-ok; encoded form, ready for writing to a file; set during
+ * {@code null-ok;} encoded form, ready for writing to a file; set during
* {@link #place0}
*/
private byte[] encodedForm;
@@ -88,7 +88,7 @@
* ignoring all other aspects of the elements. This is only valid
* to use after type id indices are known.
*
- * @param array non-null; array to sort
+ * @param array {@code non-null;} array to sort
*/
public static void sortByTypeIdIndex(AnnotationItem[] array) {
Arrays.sort(array, TYPE_ID_SORTER);
@@ -97,7 +97,7 @@
/**
* Constructs an instance.
*
- * @param annotation non-null; annotation to represent
+ * @param annotation {@code non-null;} annotation to represent
*/
public AnnotationItem(Annotation annotation) {
/*
@@ -167,8 +167,8 @@
* output, that consumes no bytes of output. This is for annotating
* a reference to this instance at the point of the reference.
*
- * @param out non-null; where to output to
- * @param prefix non-null; prefix for each line of output
+ * @param out {@code non-null;} where to output to
+ * @param prefix {@code non-null;} prefix for each line of output
*/
public void annotateTo(AnnotatedOutput out, String prefix) {
out.annotate(0, prefix + "visibility: " +
diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
index f03cc08..2ff005a 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationSetItem.java
@@ -28,14 +28,14 @@
/** the required alignment for instances of this class */
private static final int ALIGNMENT = 4;
- /** the size of an entry int the set: one <code>uint</code> */
+ /** the size of an entry int the set: one {@code uint} */
private static final int ENTRY_WRITE_SIZE = 4;
- /** non-null; the set of annotations */
+ /** {@code non-null;} the set of annotations */
private final Annotations annotations;
/**
- * non-null; set of annotations as individual items in an array.
+ * {@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
* writing.
*/
@@ -44,7 +44,7 @@
/**
* Constructs an instance.
*
- * @param annotations non-null; set of annotations
+ * @param annotations {@code non-null;} set of annotations
*/
public AnnotationSetItem(Annotations annotations) {
super(ALIGNMENT, writeSize(annotations));
@@ -62,8 +62,8 @@
/**
* Gets the write size for the given set.
*
- * @param annotations non-null; the set
- * @return > 0; the write size
+ * @param annotations {@code non-null;} the set
+ * @return {@code > 0;} the write size
*/
private static int writeSize(Annotations annotations) {
// This includes an int size at the start of the list.
@@ -79,7 +79,7 @@
/**
* Gets the underlying annotations of this instance
*
- * @return non-null; the annotations
+ * @return {@code non-null;} the annotations
*/
public Annotations getAnnotations() {
return annotations;
diff --git a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
index 422e2f0..1427e6a 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationSetRefItem.java
@@ -29,13 +29,13 @@
/** write size of this class, in bytes */
private static final int WRITE_SIZE = 4;
- /** non-null; the annotation set to refer to */
+ /** {@code non-null;} the annotation set to refer to */
private AnnotationSetItem annotations;
/**
* Constructs an instance.
*
- * @param annotations non-null; the annotation set to refer to
+ * @param annotations {@code non-null;} the annotation set to refer to
*/
public AnnotationSetRefItem(AnnotationSetItem annotations) {
super(ALIGNMENT, WRITE_SIZE);
diff --git a/dx/src/com/android/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
index c9d7968..8431d35 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationUtils.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
@@ -38,41 +38,41 @@
* Utility class for dealing with annotations.
*/
public final class AnnotationUtils {
- /** non-null; type for <code>AnnotationDefault</code> annotations */
+ /** {@code non-null;} type for {@code AnnotationDefault} annotations */
private static final CstType ANNOTATION_DEFAULT_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;"));
- /** non-null; type for <code>EnclosingClass</code> annotations */
+ /** {@code non-null;} type for {@code EnclosingClass} annotations */
private static final CstType ENCLOSING_CLASS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;"));
- /** non-null; type for <code>EnclosingMethod</code> annotations */
+ /** {@code non-null;} type for {@code EnclosingMethod} annotations */
private static final CstType ENCLOSING_METHOD_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;"));
- /** non-null; type for <code>InnerClass</code> annotations */
+ /** {@code non-null;} type for {@code InnerClass} annotations */
private static final CstType INNER_CLASS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;"));
- /** non-null; type for <code>MemberClasses</code> annotations */
+ /** {@code non-null;} type for {@code MemberClasses} annotations */
private static final CstType MEMBER_CLASSES_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;"));
- /** non-null; type for <code>Signature</code> annotations */
+ /** {@code non-null;} type for {@code Signature} annotations */
private static final CstType SIGNATURE_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
- /** non-null; type for <code>Throws</code> annotations */
+ /** {@code non-null;} type for {@code Throws} annotations */
private static final CstType THROWS_TYPE =
CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
- /** non-null; the UTF-8 constant <code>"accessFlags"</code> */
+ /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */
private static final CstUtf8 ACCESS_FLAGS_UTF = new CstUtf8("accessFlags");
- /** non-null; the UTF-8 constant <code>"name"</code> */
+ /** {@code non-null;} the UTF-8 constant {@code "name"} */
private static final CstUtf8 NAME_UTF = new CstUtf8("name");
- /** non-null; the UTF-8 constant <code>"value"</code> */
+ /** {@code non-null;} the UTF-8 constant {@code "value"} */
private static final CstUtf8 VALUE_UTF = new CstUtf8("value");
/**
@@ -83,10 +83,10 @@
}
/**
- * Constructs a standard <code>AnnotationDefault</code> annotation.
+ * Constructs a standard {@code AnnotationDefault} annotation.
*
- * @param defaults non-null; the defaults, itself as an annotation
- * @return non-null; the constructed annotation
+ * @param defaults {@code non-null;} the defaults, itself as an annotation
+ * @return {@code non-null;} the constructed annotation
*/
public static Annotation makeAnnotationDefault(Annotation defaults) {
Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM);
@@ -97,10 +97,10 @@
}
/**
- * Constructs a standard <code>EnclosingClass</code> annotation.
+ * Constructs a standard {@code EnclosingClass} annotation.
*
- * @param clazz non-null; the enclosing class
- * @return non-null; the annotation
+ * @param clazz {@code non-null;} the enclosing class
+ * @return {@code non-null;} the annotation
*/
public static Annotation makeEnclosingClass(CstType clazz) {
Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM);
@@ -111,10 +111,10 @@
}
/**
- * Constructs a standard <code>EnclosingMethod</code> annotation.
+ * Constructs a standard {@code EnclosingMethod} annotation.
*
- * @param method non-null; the enclosing method
- * @return non-null; the annotation
+ * @param method {@code non-null;} the enclosing method
+ * @return {@code non-null;} the annotation
*/
public static Annotation makeEnclosingMethod(CstMethodRef method) {
Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM);
@@ -125,12 +125,12 @@
}
/**
- * Constructs a standard <code>InnerClass</code> annotation.
+ * Constructs a standard {@code InnerClass} annotation.
*
- * @param name null-ok; the original name of the class, or
- * <code>null</code> to represent an anonymous class
+ * @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
- * @return non-null; the annotation
+ * @return {@code non-null;} the annotation
*/
public static Annotation makeInnerClass(CstUtf8 name, int accessFlags) {
Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM);
@@ -145,10 +145,10 @@
}
/**
- * Constructs a standard <code>MemberClasses</code> annotation.
+ * Constructs a standard {@code MemberClasses} annotation.
*
- * @param types non-null; the list of (the types of) the member classes
- * @return non-null; the annotation
+ * @param types {@code non-null;} the list of (the types of) the member classes
+ * @return {@code non-null;} the annotation
*/
public static Annotation makeMemberClasses(TypeList types) {
CstArray array = makeCstArray(types);
@@ -159,10 +159,10 @@
}
/**
- * Constructs a standard <code>Signature</code> annotation.
+ * Constructs a standard {@code Signature} annotation.
*
- * @param signature non-null; the signature string
- * @return non-null; the annotation
+ * @param signature {@code non-null;} the signature string
+ * @return {@code non-null;} the annotation
*/
public static Annotation makeSignature(CstUtf8 signature) {
Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM);
@@ -221,10 +221,10 @@
}
/**
- * Constructs a standard <code>Throws</code> annotation.
+ * Constructs a standard {@code Throws} annotation.
*
- * @param types non-null; the list of thrown types
- * @return non-null; the annotation
+ * @param types {@code non-null;} the list of thrown types
+ * @return {@code non-null;} the annotation
*/
public static Annotation makeThrows(TypeList types) {
CstArray array = makeCstArray(types);
@@ -237,8 +237,8 @@
/**
* Converts a {@link TypeList} to a {@link CstArray}.
*
- * @param types non-null; the type list
- * @return non-null; the corresponding array constant
+ * @param types {@code non-null;} the type list
+ * @return {@code non-null;} the corresponding array constant
*/
private static CstArray makeCstArray(TypeList types) {
int size = types.size();
diff --git a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
index 4521e4c..d55195f 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationsDirectoryItem.java
@@ -40,16 +40,16 @@
/** write size of a list element, in bytes */
private static final int ELEMENT_SIZE = 8;
- /** null-ok; the class-level annotations, if any */
+ /** {@code null-ok;} the class-level annotations, if any */
private AnnotationSetItem classAnnotations;
- /** null-ok; the annotated fields, if any */
+ /** {@code null-ok;} the annotated fields, if any */
private ArrayList<FieldAnnotationStruct> fieldAnnotations;
- /** null-ok; the annotated methods, if any */
+ /** {@code null-ok;} the annotated methods, if any */
private ArrayList<MethodAnnotationStruct> methodAnnotations;
- /** null-ok; the annotated parameters, if any */
+ /** {@code null-ok;} the annotated parameters, if any */
private ArrayList<ParameterAnnotationStruct> parameterAnnotations;
/**
@@ -73,7 +73,7 @@
/**
* Returns whether this item is empty (has no contents).
*
- * @return <code>true</code> if this item is empty, or <code>false</code>
+ * @return {@code true} if this item is empty, or {@code false}
* if not
*/
public boolean isEmpty() {
@@ -88,8 +88,8 @@
* interning candidates are ones that <i>only</i> have a non-null
* set of class annotations, with no other lists.
*
- * @return <code>true</code> if this is an interning candidate, or
- * <code>false</code> if not
+ * @return {@code true} if this is an interning candidate, or
+ * {@code false} if not
*/
public boolean isInternable() {
return (classAnnotations != null) &&
@@ -132,7 +132,7 @@
* 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 non-null; annotations to set for this class
+ * @param annotations {@code non-null;} annotations to set for this class
*/
public void setClassAnnotations(Annotations annotations) {
if (annotations == null) {
@@ -150,8 +150,8 @@
/**
* Adds a field annotations item to this instance.
*
- * @param field non-null; field in question
- * @param annotations non-null; associated annotations to add
+ * @param field {@code non-null;} field in question
+ * @param annotations {@code non-null;} associated annotations to add
*/
public void addFieldAnnotations(CstFieldRef field,
Annotations annotations) {
@@ -166,8 +166,8 @@
/**
* Adds a method annotations item to this instance.
*
- * @param method non-null; method in question
- * @param annotations non-null; associated annotations to add
+ * @param method {@code non-null;} method in question
+ * @param annotations {@code non-null;} associated annotations to add
*/
public void addMethodAnnotations(CstMethodRef method,
Annotations annotations) {
@@ -182,8 +182,8 @@
/**
* Adds a parameter annotations item to this instance.
*
- * @param method non-null; method in question
- * @param list non-null; associated list of annotation sets to add
+ * @param method {@code non-null;} method in question
+ * @param list {@code non-null;} associated list of annotation sets to add
*/
public void addParameterAnnotations(CstMethodRef method,
AnnotationsList list) {
@@ -198,8 +198,8 @@
* Gets the method annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
*
- * @param method non-null; the method
- * @return null-ok; the method annotations, if any
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the method annotations, if any
*/
public Annotations getMethodAnnotations(CstMethodRef method) {
if (methodAnnotations == null) {
@@ -219,8 +219,8 @@
* Gets the parameter annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
*
- * @param method non-null; the method
- * @return null-ok; the parameter annotations, if any
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the parameter annotations, if any
*/
public AnnotationsList getParameterAnnotations(CstMethodRef method) {
if (parameterAnnotations == null) {
@@ -336,11 +336,11 @@
}
/**
- * Gets the list size of the given list, or <code>0</code> if given
- * <code>null</code>.
+ * Gets the list size of the given list, or {@code 0} if given
+ * {@code null}.
*
- * @param list null-ok; the list in question
- * @return >= 0; its size
+ * @param list {@code null-ok;} the list in question
+ * @return {@code >= 0;} its size
*/
private static int listSize(ArrayList<?> list) {
if (list == null) {
@@ -354,7 +354,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 non-null; where to output to
+ * @param out {@code non-null;} where to output to
*/
/*package*/ void debugPrint(PrintWriter out) {
if (classAnnotations != null) {
diff --git a/dx/src/com/android/dx/dex/file/CatchStructs.java b/dx/src/com/android/dx/dex/file/CatchStructs.java
index b7abc3f..3412015 100644
--- a/dx/src/com/android/dx/dex/file/CatchStructs.java
+++ b/dx/src/com/android/dx/dex/file/CatchStructs.java
@@ -32,27 +32,27 @@
/**
* List of exception handlers (tuples of covered range, catch type,
* handler address) for a particular piece of code. Instances of this
- * class correspond to a <code>try_item[]</code> and a
- * <code>catch_handler_item[]</code>.
+ * class correspond to a {@code try_item[]} and a
+ * {@code catch_handler_item[]}.
*/
public final class CatchStructs {
/**
- * the size of a <code>try_item</code>: a <code>uint</code>
- * and two <code>ushort</code>s
+ * the size of a {@code try_item}: a {@code uint}
+ * and two {@code ushort}s
*/
private static final int TRY_ITEM_WRITE_SIZE = 4 + (2 * 2);
- /** non-null; code that contains the catches */
+ /** {@code non-null;} code that contains the catches */
private final DalvCode code;
/**
- * null-ok; the underlying table; set in
+ * {@code null-ok;} the underlying table; set in
* {@link #finishProcessingIfNecessary}
*/
private CatchTable table;
/**
- * null-ok; the encoded handler list, if calculated; set in
+ * {@code null-ok;} the encoded handler list, if calculated; set in
* {@link #encode}
*/
private byte[] encodedHandlers;
@@ -64,7 +64,7 @@
private int encodedHandlerHeaderSize;
/**
- * null-ok; map from handler lists to byte offsets, if calculated; set in
+ * {@code null-ok;} map from handler lists to byte offsets, if calculated; set in
* {@link #encode}
*/
private TreeMap<CatchHandlerList, Integer> handlerOffsets;
@@ -72,7 +72,7 @@
/**
* Constructs an instance.
*
- * @param code non-null; code that contains the catches
+ * @param code {@code non-null;} code that contains the catches
*/
public CatchStructs(DalvCode code) {
this.code = code;
@@ -94,7 +94,7 @@
/**
* Gets the size of the tries list, in entries.
*
- * @return >= 0; the tries list size
+ * @return {@code >= 0;} the tries list size
*/
public int triesSize() {
finishProcessingIfNecessary();
@@ -104,8 +104,8 @@
/**
* Does a human-friendly dump of this instance.
*
- * @param out non-null; where to dump
- * @param prefix non-null; prefix to attach to each line of output
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
*/
public void debugPrint(PrintWriter out, String prefix) {
annotateEntries(prefix, out, null);
@@ -114,7 +114,7 @@
/**
* Encodes the handler lists.
*
- * @param file non-null; file this instance is part of
+ * @param file {@code non-null;} file this instance is part of
*/
public void encode(DexFile file) {
finishProcessingIfNecessary();
@@ -179,7 +179,7 @@
/**
* Gets the write size of this instance, in bytes.
*
- * @return >= 0; the write size
+ * @return {@code >= 0;} the write size
*/
public int writeSize() {
return (triesSize() * TRY_ITEM_WRITE_SIZE) +
@@ -189,20 +189,17 @@
/**
* Writes this instance to the given stream.
*
- * @param file non-null; file this instance is part of
- * @param out non-null; where to write to
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
*/
public void writeTo(DexFile file, AnnotatedOutput out) {
finishProcessingIfNecessary();
- TypeIdsSection typeIds = file.getTypeIds();
- int tableSize = table.size();
- int handlersSize = handlerOffsets.size();
-
if (out.annotates()) {
annotateEntries(" ", null, out);
}
+ int tableSize = table.size();
for (int i = 0; i < tableSize; i++) {
CatchTable.Entry one = table.get(i);
int start = one.getStart();
@@ -225,12 +222,12 @@
/**
* Helper method to annotate or simply print the exception handlers.
- * Only one of <code>printTo</code> or <code>annotateTo</code> should
+ * Only one of {@code printTo} or {@code annotateTo} should
* be non-null.
*
- * @param prefix non-null; prefix for each line
- * @param printTo null-ok; where to print to
- * @param annotateTo null-ok; where to consume bytes and annotate to
+ * @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
*/
private void annotateEntries(String prefix, PrintWriter printTo,
AnnotatedOutput annotateTo) {
@@ -299,12 +296,12 @@
* Helper for {@link #annotateEntries} to annotate a catch handler list
* while consuming it.
*
- * @param handlers non-null; handlers to annotate
- * @param offset >= 0; the offset of this handler
- * @param size >= 1; the number of bytes the handlers consume
- * @param prefix non-null; prefix for each line
- * @param printTo null-ok; where to print to
- * @param annotateTo non-null; where to annotate to
+ * @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
+ * @param prefix {@code non-null;} prefix for each line
+ * @param printTo {@code null-ok;} where to print to
+ * @param annotateTo {@code non-null;} where to annotate to
*/
private static void annotateAndConsumeHandlers(CatchHandlerList handlers,
int offset, int size, String prefix, PrintWriter printTo,
diff --git a/dx/src/com/android/dx/dex/file/ClassDataItem.java b/dx/src/com/android/dx/dex/file/ClassDataItem.java
index 638daed..4823f9f 100644
--- a/dx/src/com/android/dx/dex/file/ClassDataItem.java
+++ b/dx/src/com/android/dx/dex/file/ClassDataItem.java
@@ -38,32 +38,32 @@
* Representation of all the parts of a Dalvik class that are generally
* "inflated" into an in-memory representation at runtime. Instances of
* this class are represented in a compact streamable form in a
- * <code>dex</code> file, as opposed to a random-access form.
+ * {@code dex} file, as opposed to a random-access form.
*/
public final class ClassDataItem extends OffsettedItem {
- /** non-null; what class this data is for, just for listing generation */
+ /** {@code non-null;} what class this data is for, just for listing generation */
private final CstType thisClass;
- /** non-null; list of static fields */
+ /** {@code non-null;} list of static fields */
private final ArrayList<EncodedField> staticFields;
- /** non-null; list of initial values for static fields */
+ /** {@code non-null;} list of initial values for static fields */
private final HashMap<EncodedField, Constant> staticValues;
- /** non-null; list of instance fields */
+ /** {@code non-null;} list of instance fields */
private final ArrayList<EncodedField> instanceFields;
- /** non-null; list of direct methods */
+ /** {@code non-null;} list of direct methods */
private final ArrayList<EncodedMethod> directMethods;
- /** non-null; list of virtual methods */
+ /** {@code non-null;} list of virtual methods */
private final ArrayList<EncodedMethod> virtualMethods;
- /** null-ok; static initializer list; set in {@link #addContents} */
+ /** {@code null-ok;} static initializer list; set in {@link #addContents} */
private CstArray staticValuesConstant;
/**
- * null-ok; encoded form, ready for writing to a file; set during
+ * {@code null-ok;} encoded form, ready for writing to a file; set during
* {@link #place0}
*/
private byte[] encodedForm;
@@ -72,7 +72,7 @@
* Constructs an instance. Its sets of members are initially
* empty.
*
- * @param thisClass non-null; what class this data is for, just
+ * @param thisClass {@code non-null;} what class this data is for, just
* for listing generation
*/
public ClassDataItem(CstType thisClass) {
@@ -106,8 +106,8 @@
/**
* Returns whether this instance is empty.
*
- * @return <code>true</code> if this instance is empty or
- * <code>false</code> if at least one element has been added to it
+ * @return {@code true} if this instance is empty or
+ * {@code false} if at least one element has been added to it
*/
public boolean isEmpty() {
return staticFields.isEmpty() && instanceFields.isEmpty()
@@ -117,8 +117,8 @@
/**
* Adds a static field.
*
- * @param field non-null; the field to add
- * @param value null-ok; initial value for the field, if any
+ * @param field {@code non-null;} the field to add
+ * @param value {@code null-ok;} initial value for the field, if any
*/
public void addStaticField(EncodedField field, Constant value) {
if (field == null) {
@@ -137,7 +137,7 @@
/**
* Adds an instance field.
*
- * @param field non-null; the field to add
+ * @param field {@code non-null;} the field to add
*/
public void addInstanceField(EncodedField field) {
if (field == null) {
@@ -148,9 +148,9 @@
}
/**
- * Adds a direct (<code>static</code> and/or <code>private</code>) method.
+ * Adds a direct ({@code static} and/or {@code private}) method.
*
- * @param method non-null; the method to add
+ * @param method {@code non-null;} the method to add
*/
public void addDirectMethod(EncodedMethod method) {
if (method == null) {
@@ -163,7 +163,7 @@
/**
* Adds a virtual method.
*
- * @param method non-null; the method to add
+ * @param method {@code non-null;} the method to add
*/
public void addVirtualMethod(EncodedMethod method) {
if (method == null) {
@@ -178,7 +178,7 @@
* in any way to the underlying lists contained in this instance, but
* the objects contained in the list are shared.
*
- * @return non-null; list of all methods
+ * @return {@code non-null;} list of all methods
*/
public ArrayList<EncodedMethod> getMethods() {
int sz = directMethods.size() + virtualMethods.size();
@@ -195,7 +195,7 @@
* Prints out the contents of this instance, in a debugging-friendly
* way.
*
- * @param out non-null; where to output to
+ * @param out {@code non-null;} where to output to
* @param verbose whether to be verbose with the output
*/
public void debugPrint(Writer out, boolean verbose) {
@@ -258,9 +258,9 @@
/**
* Gets a {@link CstArray} corresponding to {@link #staticValues} if
- * it contains any non-zero non-<code>null</code> values.
+ * it contains any non-zero non-{@code null} values.
*
- * @return null-ok; the corresponding constant or <code>null</code> if
+ * @return {@code null-ok;} the corresponding constant or {@code null} if
* there are no values to encode
*/
public CstArray getStaticValuesConstant() {
@@ -273,9 +273,9 @@
/**
* Gets a {@link CstArray} corresponding to {@link #staticValues} if
- * it contains any non-zero non-<code>null</code> values.
+ * it contains any non-zero non-{@code null} values.
*
- * @return null-ok; the corresponding constant or <code>null</code> if
+ * @return {@code null-ok;} the corresponding constant or {@code null} if
* there are no values to encode
*/
private CstArray makeStaticValuesConstant() {
@@ -337,13 +337,11 @@
/**
* Writes out the encoded form of this instance.
*
- * @param file non-null; file this instance is part of
- * @param out non-null; where to write to
+ * @param file {@code non-null;} file this instance is part of
+ * @param out {@code non-null;} where to write to
*/
private void encodeOutput(DexFile file, AnnotatedOutput out) {
boolean annotates = out.annotates();
- int svSize = (staticValuesConstant == null) ? 0 :
- staticValuesConstant.getList().size();
if (annotates) {
out.annotate(0, offsetString() + " class data for " +
@@ -369,10 +367,10 @@
* Helper for {@link #encodeOutput}, which writes out the given
* size value, annotating it as well (if annotations are enabled).
*
- * @param file non-null; file this instance is part of
- * @param out non-null; where to write to
- * @param label non-null; the label for the purposes of annotation
- * @param size >= 0; the size to write
+ * @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
+ * @param size {@code >= 0;} the size to write
*/
private static void encodeSize(DexFile file, AnnotatedOutput out,
String label, int size) {
@@ -389,10 +387,10 @@
* list. It also annotates the items (if any and if annotations
* are enabled).
*
- * @param file non-null; file this instance is part of
- * @param out non-null; where to write to
- * @param label non-null; the label for the purposes of annotation
- * @param list non-null; the list in question
+ * @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
+ * @param list {@code non-null;} the list in question
*/
private static void encodeList(DexFile file, AnnotatedOutput out,
String label, ArrayList<? extends EncodedMember> list) {
diff --git a/dx/src/com/android/dx/dex/file/ClassDefItem.java b/dx/src/com/android/dx/dex/file/ClassDefItem.java
index 5a0b27c..acd8cf5 100644
--- a/dx/src/com/android/dx/dex/file/ClassDefItem.java
+++ b/dx/src/com/android/dx/dex/file/ClassDefItem.java
@@ -45,47 +45,47 @@
/** size of instances when written out to a file, in bytes */
public static final int WRITE_SIZE = 32;
- /** non-null; type constant for this class */
+ /** {@code non-null;} type constant for this class */
private final CstType thisClass;
/** access flags */
private final int accessFlags;
/**
- * null-ok; superclass or <code>null</code> if this class is a/the
+ * {@code null-ok;} superclass or {@code null} if this class is a/the
* root class
*/
private final CstType superclass;
- /** null-ok; list of implemented interfaces */
+ /** {@code null-ok;} list of implemented interfaces */
private TypeListItem interfaces;
- /** null-ok; source file name or <code>null</code> if unknown */
+ /** {@code null-ok;} source file name or {@code null} if unknown */
private final CstUtf8 sourceFile;
- /** non-null; associated class data object */
+ /** {@code non-null;} associated class data object */
private final ClassDataItem classData;
/**
- * null-ok; item wrapper for the static values, initialized
+ * {@code null-ok;} item wrapper for the static values, initialized
* in {@link #addContents}
*/
private EncodedArrayItem staticValuesItem;
- /** non-null; annotations directory */
+ /** {@code non-null;} annotations directory */
private AnnotationsDirectoryItem annotationsDirectory;
/**
* Constructs an instance. Its sets of members and annotations are
* initially empty.
*
- * @param thisClass non-null; type constant for this class
+ * @param thisClass {@code non-null;} type constant for this class
* @param accessFlags access flags
- * @param superclass null-ok; superclass or <code>null</code> if
+ * @param superclass {@code null-ok;} superclass or {@code null} if
* this class is a/the root class
- * @param interfaces non-null; list of implemented interfaces
- * @param sourceFile null-ok; source file name or
- * <code>null</code> if unknown
+ * @param interfaces {@code non-null;} list of implemented interfaces
+ * @param sourceFile {@code null-ok;} source file name or
+ * {@code null} if unknown
*/
public ClassDefItem(CstType thisClass, int accessFlags,
CstType superclass, TypeList interfaces, CstUtf8 sourceFile) {
@@ -223,7 +223,7 @@
/**
* Gets the constant corresponding to this class.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public CstType getThisClass() {
return thisClass;
@@ -241,7 +241,7 @@
/**
* Gets the superclass.
*
- * @return null-ok; the superclass or <code>null</code> if
+ * @return {@code null-ok;} the superclass or {@code null} if
* this class is a/the root class
*/
public CstType getSuperclass() {
@@ -251,7 +251,7 @@
/**
* Gets the list of interfaces implemented.
*
- * @return non-null; the interfaces list
+ * @return {@code non-null;} the interfaces list
*/
public TypeList getInterfaces() {
if (interfaces == null) {
@@ -264,7 +264,7 @@
/**
* Gets the source file name.
*
- * @return null-ok; the source file name or <code>null</code> if unknown
+ * @return {@code null-ok;} the source file name or {@code null} if unknown
*/
public CstUtf8 getSourceFile() {
return sourceFile;
@@ -273,8 +273,8 @@
/**
* Adds a static field.
*
- * @param field non-null; the field to add
- * @param value null-ok; initial value for the field, if any
+ * @param field {@code non-null;} the field to add
+ * @param value {@code null-ok;} initial value for the field, if any
*/
public void addStaticField(EncodedField field, Constant value) {
classData.addStaticField(field, value);
@@ -283,16 +283,16 @@
/**
* Adds an instance field.
*
- * @param field non-null; the field to add
+ * @param field {@code non-null;} the field to add
*/
public void addInstanceField(EncodedField field) {
classData.addInstanceField(field);
}
/**
- * Adds a direct (<code>static</code> and/or <code>private</code>) method.
+ * Adds a direct ({@code static} and/or {@code private}) method.
*
- * @param method non-null; the method to add
+ * @param method {@code non-null;} the method to add
*/
public void addDirectMethod(EncodedMethod method) {
classData.addDirectMethod(method);
@@ -301,7 +301,7 @@
/**
* Adds a virtual method.
*
- * @param method non-null; the method to add
+ * @param method {@code non-null;} the method to add
*/
public void addVirtualMethod(EncodedMethod method) {
classData.addVirtualMethod(method);
@@ -312,7 +312,7 @@
* in any way to the underlying lists contained in this instance, but
* the objects contained in the list are shared.
*
- * @return non-null; list of all methods
+ * @return {@code non-null;} list of all methods
*/
public ArrayList<EncodedMethod> getMethods() {
return classData.getMethods();
@@ -323,7 +323,7 @@
* 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 non-null; annotations to set for this class
+ * @param annotations {@code non-null;} annotations to set for this class
*/
public void setClassAnnotations(Annotations annotations) {
annotationsDirectory.setClassAnnotations(annotations);
@@ -332,8 +332,8 @@
/**
* Adds a field annotations item to this class.
*
- * @param field non-null; field in question
- * @param annotations non-null; associated annotations to add
+ * @param field {@code non-null;} field in question
+ * @param annotations {@code non-null;} associated annotations to add
*/
public void addFieldAnnotations(CstFieldRef field,
Annotations annotations) {
@@ -343,8 +343,8 @@
/**
* Adds a method annotations item to this class.
*
- * @param method non-null; method in question
- * @param annotations non-null; associated annotations to add
+ * @param method {@code non-null;} method in question
+ * @param annotations {@code non-null;} associated annotations to add
*/
public void addMethodAnnotations(CstMethodRef method,
Annotations annotations) {
@@ -354,8 +354,8 @@
/**
* Adds a parameter annotations item to this class.
*
- * @param method non-null; method in question
- * @param list non-null; associated list of annotation sets to add
+ * @param method {@code non-null;} method in question
+ * @param list {@code non-null;} associated list of annotation sets to add
*/
public void addParameterAnnotations(CstMethodRef method,
AnnotationsList list) {
@@ -366,8 +366,8 @@
* Gets the method annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
*
- * @param method non-null; the method
- * @return null-ok; the method annotations, if any
+ * @param method {@code non-null;} the method
+ * @return {@code null-ok;} the method annotations, if any
*/
public Annotations getMethodAnnotations(CstMethodRef method) {
return annotationsDirectory.getMethodAnnotations(method);
@@ -377,8 +377,8 @@
* Gets the parameter annotations for a given method, if any. This is
* meant for use by debugging / dumping code.
*
- * @param method non-null; the method
- * @return null-ok; the parameter annotations, if any
+ * @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);
@@ -388,7 +388,7 @@
* Prints out the contents of this instance, in a debugging-friendly
* way.
*
- * @param out non-null; where to output to
+ * @param out {@code non-null;} where to output to
* @param verbose whether to be verbose with the output
*/
public void debugPrint(Writer out, boolean verbose) {
diff --git a/dx/src/com/android/dx/dex/file/ClassDefsSection.java b/dx/src/com/android/dx/dex/file/ClassDefsSection.java
index cf61b47..e8efd57 100644
--- a/dx/src/com/android/dx/dex/file/ClassDefsSection.java
+++ b/dx/src/com/android/dx/dex/file/ClassDefsSection.java
@@ -28,22 +28,22 @@
import java.util.TreeMap;
/**
- * Class definitions list section of a <code>.dex</code> file.
+ * Class definitions list section of a {@code .dex} file.
*/
public final class ClassDefsSection extends UniformItemSection {
/**
- * non-null; map from type constants for classes to {@link
+ * {@code non-null;} map from type constants for classes to {@link
* ClassDefItem} instances that define those classes
*/
private final TreeMap<Type, ClassDefItem> classDefs;
- /** null-ok; ordered list of classes; set in {@link #orderItems} */
+ /** {@code null-ok;} ordered list of classes; set in {@link #orderItems} */
private ArrayList<ClassDefItem> orderedDefs;
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public ClassDefsSection(DexFile file) {
super("class_defs", file, 4);
@@ -84,7 +84,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -105,7 +105,7 @@
* Adds an element to this instance. It is illegal to attempt to add more
* than one class with the same name.
*
- * @param clazz non-null; the class def to add
+ * @param clazz {@code non-null;} the class def to add
*/
public void add(ClassDefItem clazz) {
Type type;
@@ -149,11 +149,11 @@
* Helper for {@link #orderItems}, which recursively assigns indices
* to classes.
*
- * @param type null-ok; type ref to assign, if any
- * @param idx >= 0; the next index to assign
+ * @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
* throw an exception indicating class definition circularity
- * @return >= 0; the next index to assign
+ * @return {@code >= 0;} the next index to assign
*/
private int orderItems0(Type type, int idx, int maxDepth) {
ClassDefItem c = classDefs.get(type);
diff --git a/dx/src/com/android/dx/dex/file/CodeItem.java b/dx/src/com/android/dx/dex/file/CodeItem.java
index dc0bb52..ab7abbe 100644
--- a/dx/src/com/android/dx/dex/file/CodeItem.java
+++ b/dx/src/com/android/dx/dex/file/CodeItem.java
@@ -39,7 +39,7 @@
/**
* Representation of all the parts needed for concrete methods in a
- * <code>dex</code> file.
+ * {@code dex} file.
*/
public final class CodeItem extends OffsettedItem {
/** file alignment of this class, in bytes */
@@ -48,26 +48,26 @@
/** write size of the header of this class, in bytes */
private static final int HEADER_SIZE = 16;
- /** non-null; method that this code implements */
+ /** {@code non-null;} method that this code implements */
private final CstMethodRef ref;
- /** non-null; the bytecode instructions and associated data */
+ /** {@code non-null;} the bytecode instructions and associated data */
private final DalvCode code;
- /** null-ok; the catches, if needed; set in {@link #addContents} */
+ /** {@code null-ok;} the catches, if needed; set in {@link #addContents} */
private CatchStructs catches;
- /** whether this instance is for a <code>static</code> method */
+ /** whether this instance is for a {@code static} method */
private final boolean isStatic;
/**
- * non-null; list of possibly-thrown exceptions; just used in
+ * {@code non-null;} list of possibly-thrown exceptions; just used in
* generating debugging output (listings)
*/
private final TypeList throwsList;
/**
- * null-ok; the debug info or <code>null</code> if there is none;
+ * {@code null-ok;} the debug info or {@code null} if there is none;
* set in {@link #addContents}
*/
private DebugInfoItem debugInfo;
@@ -75,11 +75,11 @@
/**
* Constructs an instance.
*
- * @param ref non-null; method that this code implements
- * @param code non-null; the underlying code
- * @param isStatic whether this instance is for a <code>static</code>
+ * @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}
* method
- * @param throwsList non-null; list of possibly-thrown exceptions,
+ * @param throwsList {@code non-null;} list of possibly-thrown exceptions,
* just used in generating debugging output (listings)
*/
public CodeItem(CstMethodRef ref, DalvCode code, boolean isStatic,
@@ -114,7 +114,6 @@
/** {@inheritDoc} */
public void addContents(DexFile file) {
- MixedItemSection wordData = file.getWordData();
MixedItemSection byteData = file.getByteData();
TypeIdsSection typeIds = file.getTypeIds();
@@ -150,7 +149,7 @@
/**
* Gets the reference to the method this instance implements.
*
- * @return non-null; the method reference
+ * @return {@code non-null;} the method reference
*/
public CstMethodRef getRef() {
return ref;
@@ -159,8 +158,8 @@
/**
* Does a human-friendly dump of this instance.
*
- * @param out non-null; where to dump
- * @param prefix non-null; per-line prefix to use
+ * @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
*/
public void debugPrint(PrintWriter out, String prefix, boolean verbose) {
@@ -292,8 +291,8 @@
/**
* Helper for {@link #writeTo0} which writes out the actual bytecode.
*
- * @param file non-null; file we are part of
- * @param out non-null; where to write to
+ * @param file {@code non-null;} file we are part of
+ * @param out {@code non-null;} where to write to
*/
private void writeCodes(DexFile file, AnnotatedOutput out) {
DalvInsnList insns = code.getInsns();
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java b/dx/src/com/android/dx/dex/file/DebugInfoConstants.java
index 010acb4..78b6b04 100644
--- a/dx/src/com/android/dx/dex/file/DebugInfoConstants.java
+++ b/dx/src/com/android/dx/dex/file/DebugInfoConstants.java
@@ -110,8 +110,8 @@
* next position entry that is added should be considered the end of
* a method prologue (an appropriate place for a method breakpoint).<p>
*
- * The prologue_end register is cleared by any special (>= OPCODE_BASE)
- * opcode.
+ * The prologue_end register is cleared by any special
+ * ({@code >= OPCODE_BASE}) opcode.
*/
static final int DBG_SET_PROLOGUE_END = 0x07;
@@ -121,8 +121,8 @@
* a method epilogue (an appropriate place to suspend execution before
* method exit).<p>
*
- * The epilogue_begin register is cleared by any special (>= OPCODE_BASE)
- * opcode.
+ * The epilogue_begin register is cleared by any special
+ * ({@code >= OPCODE_BASE}) opcode.
*/
static final int DBG_SET_EPILOGUE_BEGIN = 0x08;
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
index 3ffd276..cd20055 100644
--- a/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
+++ b/dx/src/com/android/dx/dex/file/DebugInfoDecoder.java
@@ -38,7 +38,7 @@
/**
* A decoder for the dex debug info state machine format.
* This code exists mostly as a reference implementation and test for
- * for the <code>DebugInfoEncoder</code>
+ * for the {@code DebugInfoEncoder}
*/
public class DebugInfoDecoder {
/** encoded debug info */
@@ -180,7 +180,7 @@
/**
* Gets the decoded positions list.
- * Valid after calling <code>decode</code>.
+ * Valid after calling {@code decode}.
*
* @return positions list in ascending address order.
*/
@@ -190,7 +190,7 @@
/**
* Gets the decoded locals list, in ascending start-address order.
- * Valid after calling <code>decode</code>.
+ * Valid after calling {@code decode}.
*
* @return locals list in ascending address order.
*/
@@ -227,7 +227,7 @@
/**
* Gets the register that begins the method's parameter range (including
* the 'this' parameter for non-static methods). The range continues until
- * <code>regSize</code>
+ * {@code regSize}
*
* @return register as noted above.
*/
@@ -416,9 +416,9 @@
* encoder.
*
* @param info encoded debug info
- * @param file non-null; file to refer to during decoding
- * @param ref non-null; method whose info is being decoded
- * @param code non-null; original code object that was encoded
+ * @param file {@code non-null;} file to refer to during decoding
+ * @param ref {@code non-null;} method whose info is being decoded
+ * @param code {@code non-null;} original code object that was encoded
* @param isStatic whether the method is static
*/
public static void validateEncode(byte[] info, DexFile file,
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java b/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java
index 780e18d..1cd24af 100644
--- a/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java
+++ b/dx/src/com/android/dx/dex/file/DebugInfoEncoder.java
@@ -46,19 +46,19 @@
* <li> signed LEB128: initial value for line register.
* <li> n instances of signed LEB128: string indicies (offset by 1)
* for each method argument in left-to-right order
- * with <code>this</code> excluded. A value of '0' indicates "no name"
+ * with {@code this} excluded. A value of '0' indicates "no name"
* <li> A sequence of special or normal opcodes as defined in
- * <code>DebugInfoConstants</code>.
- * <li> A single terminating <code>OP_END_SEQUENCE</code>
+ * {@code DebugInfoConstants}.
+ * <li> A single terminating {@code OP_END_SEQUENCE}
* </ol>
*/
public final class DebugInfoEncoder {
private static final boolean DEBUG = false;
- /** null-ok; positions (line numbers) to encode */
+ /** {@code null-ok;} positions (line numbers) to encode */
private final PositionList positions;
- /** null-ok; local variables to encode */
+ /** {@code null-ok;} local variables to encode */
private final LocalList locals;
private final ByteArrayAnnotatedOutput output;
@@ -96,33 +96,32 @@
/**
* Creates an instance.
*
- * @param pl null-ok; positions (line numbers) to encode
- * @param ll null-ok; local variables to encode
- * @param file null-ok; may only be <code>null</code> if simply using
+ * @param positions {@code null-ok;} positions (line numbers) to encode
+ * @param locals {@code null-ok;} local variables to encode
+ * @param file {@code null-ok;} may only be {@code null} if simply using
* this class to do a debug print
* @param codeSize
* @param regSize
* @param isStatic
* @param ref
*/
- public DebugInfoEncoder(PositionList pl, LocalList ll,
+ public DebugInfoEncoder(PositionList positions, LocalList locals,
DexFile file, int codeSize, int regSize,
boolean isStatic, CstMethodRef ref) {
- this.positions = pl;
- this.locals = ll;
+ this.positions = positions;
+ this.locals = locals;
this.file = file;
- output = new ByteArrayAnnotatedOutput();
this.desc = ref.getPrototype();
this.isStatic = isStatic;
-
this.codeSize = codeSize;
this.regSize = regSize;
+ output = new ByteArrayAnnotatedOutput();
lastEntryForReg = new LocalList.Entry[regSize];
}
/**
- * Annotates or writes a message to the <code>debugPrint</code> writer
+ * Annotates or writes a message to the {@code debugPrint} writer
* if applicable.
*
* @param length the number of bytes associated with this message
@@ -146,8 +145,8 @@
* Converts this (PositionList, LocalList) pair into a state machine
* sequence.
*
- * @return encoded byte sequence without padding and
- * terminated with a <code>'\00'</code>
+ * @return {@code non-null;} encoded byte sequence without padding and
+ * terminated with a {@code 0x00} byte
*/
public byte[] convert() {
try {
@@ -169,15 +168,15 @@
/**
* Converts and produces annotations on a stream. Does not write
- * actual bits to the <code>AnnotatedOutput</code>.
+ * actual bits to the {@code AnnotatedOutput}.
*
- * @param prefix null-ok; prefix to attach to each line of output
- * @param debugPrint null-ok; if specified, an alternate output for
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ * @param debugPrint {@code null-ok;} if specified, an alternate output for
* annotations
- * @param out null-ok; if specified, where annotations should go
+ * @param out {@code null-ok;} if specified, where annotations should go
* @param consume whether to claim to have consumed output for
- * <code>out</code>
- * @return output sequence
+ * {@code out}
+ * @return {@code non-null;} encoded output
*/
public byte[] convertAndAnnotate(String prefix, PrintWriter debugPrint,
AnnotatedOutput out, boolean consume) {
@@ -190,7 +189,7 @@
return result;
}
-
+
private byte[] convert0() throws IOException {
ArrayList<PositionList.Entry> sortedPositions = buildSortedPositions();
ArrayList<LocalList.Entry> methodArgs = extractMethodArguments();
@@ -204,21 +203,22 @@
annotate(1, String.format("%04x: prologue end",address));
}
- int szp = sortedPositions.size();
- int szl = locals.size();
+ int positionsSz = sortedPositions.size();
+ int localsSz = locals.size();
// Current index in sortedPositions
- int curp = 0;
+ int curPositionIdx = 0;
// Current index in locals
- int curl = 0;
+ int curLocalIdx = 0;
for (;;) {
/*
* Emit any information for the current address.
*/
- curl = emitLocalsAtAddress(curl);
- curp = emitPositionsAtAddress(curp, sortedPositions);
+ curLocalIdx = emitLocalsAtAddress(curLocalIdx);
+ curPositionIdx =
+ emitPositionsAtAddress(curPositionIdx, sortedPositions);
/*
* Figure out what the next important address is.
@@ -227,12 +227,12 @@
int nextAddrL = Integer.MAX_VALUE; // local variable
int nextAddrP = Integer.MAX_VALUE; // position (line number)
- if (curl < szl) {
- nextAddrL = locals.get(curl).getAddress();
+ if (curLocalIdx < localsSz) {
+ nextAddrL = locals.get(curLocalIdx).getAddress();
}
- if (curp < szp) {
- nextAddrP = sortedPositions.get(curp).getAddress();
+ if (curPositionIdx < positionsSz) {
+ nextAddrP = sortedPositions.get(curPositionIdx).getAddress();
}
int next = Math.min(nextAddrP, nextAddrL);
@@ -249,12 +249,12 @@
if (next == codeSize
&& nextAddrL == Integer.MAX_VALUE
&& nextAddrP == Integer.MAX_VALUE) {
- break;
+ break;
}
if (next == nextAddrP) {
// Combined advance PC + position entry
- emitPosition(sortedPositions.get(curp++));
+ emitPosition(sortedPositions.get(curPositionIdx++));
} else {
emitAdvancePc(next - address);
}
@@ -271,96 +271,96 @@
* locals} and including all subsequent activity at the same
* address.
*
- * @param curl Current index in locals
- * @return new value for <code>curl</code>
+ * @param curLocalIdx Current index in locals
+ * @return new value for {@code curLocalIdx}
* @throws IOException
*/
- private int emitLocalsAtAddress(int curl)
+ private int emitLocalsAtAddress(int curLocalIdx)
throws IOException {
int sz = locals.size();
// TODO: Don't emit ends implied by starts.
- while ((curl < sz)
- && (locals.get(curl).getAddress() == address)) {
- LocalList.Entry lle = locals.get(curl++);
- int reg = lle.getRegister();
- LocalList.Entry prevlle = lastEntryForReg[reg];
+ while ((curLocalIdx < sz)
+ && (locals.get(curLocalIdx).getAddress() == address)) {
+ LocalList.Entry entry = locals.get(curLocalIdx++);
+ int reg = entry.getRegister();
+ LocalList.Entry prevEntry = lastEntryForReg[reg];
- if (lle == prevlle) {
+ if (entry == prevEntry) {
/*
* Here we ignore locals entries for parameters,
* which have already been represented and placed in the
* lastEntryForReg array.
*/
continue;
- }
+ }
// At this point we have a new entry one way or another.
- lastEntryForReg[reg] = lle;
+ lastEntryForReg[reg] = entry;
- if (lle.isStart()) {
- if ((prevlle != null) && lle.matches(prevlle)) {
+ if (entry.isStart()) {
+ if ((prevEntry != null) && entry.matches(prevEntry)) {
/*
* The previous local in this register has the same
* name and type as the one being introduced now, so
* use the more efficient "restart" form.
*/
- if (prevlle.isStart()) {
+ if (prevEntry.isStart()) {
/*
* We should never be handed a start when a
* a matching local is already active.
*/
throw new RuntimeException("shouldn't happen");
}
- emitLocalRestart(lle);
+ emitLocalRestart(entry);
} else {
- emitLocalStart(lle);
+ emitLocalStart(entry);
}
} else {
/*
* Only emit a local end if it is *not* due to a direct
* replacement. Direct replacements imply an end of the
* previous local in the same register.
- *
+ *
* TODO: Make sure the runtime can deal with implied
* local ends from category-2 interactions, and when so,
* also stop emitting local ends for those cases.
*/
- if (lle.getDisposition()
+ if (entry.getDisposition()
!= LocalList.Disposition.END_REPLACED) {
- emitLocalEnd(lle);
+ emitLocalEnd(entry);
}
}
}
- return curl;
+ return curLocalIdx;
}
/**
- * Emits all positions that occur at the current <code>address</code>
+ * Emits all positions that occur at the current {@code address}
*
- * @param curp Current index in sortedPositions
+ * @param curPositionIdx Current index in sortedPositions
* @param sortedPositions positions, sorted by ascending address
- * @return new value for <code>curp</code>
+ * @return new value for {@code curPositionIdx}
* @throws IOException
*/
- private int emitPositionsAtAddress(int curp,
+ private int emitPositionsAtAddress(int curPositionIdx,
ArrayList<PositionList.Entry> sortedPositions)
throws IOException {
-
- int szp = sortedPositions.size();
- while (curp < szp
- && sortedPositions.get(curp).getAddress() == address) {
- emitPosition(sortedPositions.get(curp++));
+ int positionsSz = sortedPositions.size();
+ while ((curPositionIdx < positionsSz)
+ && (sortedPositions.get(curPositionIdx).getAddress()
+ == address)) {
+ emitPosition(sortedPositions.get(curPositionIdx++));
}
- return curp;
+ return curPositionIdx;
}
/**
* Emits the header sequence, which consists of LEB128-encoded initial
* line number and string indicies for names of all non-"this" arguments.
- *
+ *
* @param sortedPositions positions, sorted by ascending address
* @param methodArgs local list entries for method argumens arguments,
* in left-to-right order omitting "this"
@@ -392,7 +392,7 @@
* entry for the 'this' pointer.
*/
if (!isStatic) {
- for (LocalList.Entry arg: methodArgs) {
+ for (LocalList.Entry arg : methodArgs) {
if (curParam == arg.getRegister()) {
lastEntryForReg[curParam] = arg;
break;
@@ -406,7 +406,7 @@
output.writeUnsignedLeb128(szParamTypes);
if (annotate) {
- annotate(output.getCursor() - mark,
+ annotate(output.getCursor() - mark,
String.format("parameters_size: %04x", szParamTypes));
}
@@ -420,7 +420,7 @@
mark = output.getCursor();
- for (LocalList.Entry arg: methodArgs) {
+ for (LocalList.Entry arg : methodArgs) {
if (curParam == arg.getRegister()) {
found = arg;
@@ -507,7 +507,7 @@
/**
* Gets the register that begins the method's parameter range (including
* the 'this' parameter for non-static methods). The range continues until
- * <code>regSize</code>
+ * {@code regSize}
*
* @return register as noted above
*/
@@ -521,7 +521,7 @@
* from the input list and sorted by ascending register in the
* returned list.
*
- * @return list of non-<code>this</code> method argument locals,
+ * @return list of non-{@code this} method argument locals,
* sorted by ascending register
*/
private ArrayList<LocalList.Entry> extractMethodArguments() {
@@ -566,8 +566,8 @@
* Returns a string representation of this LocalList entry that is
* appropriate for emitting as an annotation.
*
- * @param e non-null; entry
- * @return non-null; annotation string
+ * @param e {@code non-null;} entry
+ * @return {@code non-null;} annotation string
*/
private String entryAnnotationString(LocalList.Entry e) {
StringBuilder sb = new StringBuilder();
@@ -633,7 +633,7 @@
* null symbol is used in some cases by the parameter name list
* at the beginning of the sequence.
*
- * @param string null-ok; string to emit
+ * @param string {@code null-ok;} string to emit
* @throws IOException
*/
private void emitStringIndex(CstUtf8 string) throws IOException {
@@ -654,7 +654,7 @@
* Emits a type index as an unsigned LEB128. The actual value written
* is shifted by 1, so that the '0' value is reserved for "null".
*
- * @param type null-ok; type to emit
+ * @param type {@code null-ok;} type to emit
* @throws IOException
*/
private void emitTypeIndex(CstType type) throws IOException {
@@ -739,7 +739,7 @@
/**
* Emits a {@link DebugInfoConstants#DBG_END_LOCAL DBG_END_LOCAL} sequence.
*
- * @param entry entry non-null; entry associated with end.
+ * @param entry {@code entry non-null;} entry associated with end.
* @throws IOException
*/
private void emitLocalEnd(LocalList.Entry entry)
@@ -823,16 +823,17 @@
* Essentially the same as described in "DWARF Debugging Format Version 3"
* section 6.2.5.1.
*
- * @param deltaLines >= DBG_LINE_BASE and <= DBG_LINE_BASE +
- * DBG_LINE_RANGE, the line change to encode
- * @param deltaAddress >= 0; the address change to encode
- * @return <= 0xff if in range, otherwise parameters are out of range
+ * @param deltaLines {@code >= DBG_LINE_BASE, <= DBG_LINE_BASE +
+ * DBG_LINE_RANGE;} the line change to encode
+ * @param deltaAddress {@code >= 0;} the address change to encode
+ * @return {@code <= 0xff} if in range, otherwise parameters are out
+ * of range
*/
private static int computeOpcode(int deltaLines, int deltaAddress) {
if (deltaLines < DBG_LINE_BASE
|| deltaLines > (DBG_LINE_BASE + DBG_LINE_RANGE -1)) {
- throw new RuntimeException("Parameter out of range");
+ throw new RuntimeException("Parameter out of range");
}
return (deltaLines - DBG_LINE_BASE)
@@ -864,10 +865,10 @@
}
/**
- * Emits an {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
+ * Emits an {@link DebugInfoConstants#DBG_ADVANCE_PC DBG_ADVANCE_PC}
* sequence.
*
- * @param deltaAddress >= 0 amount to change program counter by
+ * @param deltaAddress {@code >= 0;} amount to change program counter by
* @throws IOException
*/
private void emitAdvancePc(int deltaAddress) throws IOException {
@@ -890,8 +891,9 @@
/**
* Emits an unsigned LEB128 value.
*
- * @param n >= 0 vallue to emit. Note that, although this can represent
- * integers larger than Integer.MAX_VALUE, we currently don't allow that.
+ * @param n {@code >= 0;} value to emit. Note that, although this can
+ * represent integers larger than Integer.MAX_VALUE, we currently don't
+ * allow that.
* @throws IOException
*/
private void emitUnsignedLeb128(int n) throws IOException {
diff --git a/dx/src/com/android/dx/dex/file/DebugInfoItem.java b/dx/src/com/android/dx/dex/file/DebugInfoItem.java
index 0e4329b..1c32bd7 100644
--- a/dx/src/com/android/dx/dex/file/DebugInfoItem.java
+++ b/dx/src/com/android/dx/dex/file/DebugInfoItem.java
@@ -34,7 +34,7 @@
private static final boolean ENABLE_ENCODER_SELF_CHECK = false;
- /** non-null; the code this item represents */
+ /** {@code non-null;} the code this item represents */
private final DalvCode code;
private byte[] encoded;
@@ -93,9 +93,9 @@
* directly after a code dump (with the real local list actually
* existing elsewhere in the output).
*
- * @param file non-null; the file to use for referencing other sections
- * @param out non-null; where to annotate to
- * @param prefix null-ok; prefix to attach to each line of output
+ * @param file {@code non-null;} the file to use for referencing other sections
+ * @param out {@code non-null;} where to annotate to
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
*/
public void annotateTo(DexFile file, AnnotatedOutput out, String prefix) {
encode(file, prefix, null, out, false);
@@ -104,8 +104,8 @@
/**
* Does a human-friendly dump of this instance.
*
- * @param out non-null; where to dump
- * @param prefix non-null; prefix to attach to each line of output
+ * @param out {@code non-null;} where to dump
+ * @param prefix {@code non-null;} prefix to attach to each line of output
*/
public void debugPrint(PrintWriter out, String prefix) {
encode(null, prefix, out, null, false);
@@ -130,14 +130,14 @@
/**
* Performs debug info encoding.
*
- * @param file null-ok; file to refer to during encoding
- * @param prefix null-ok; prefix to attach to each line of output
- * @param debugPrint null-ok; if specified, an alternate output for
+ * @param file {@code null-ok;} file to refer to during encoding
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ * @param debugPrint {@code null-ok;} if specified, an alternate output for
* annotations
- * @param out null-ok; if specified, where annotations should go
+ * @param out {@code null-ok;} if specified, where annotations should go
* @param consume whether to claim to have consumed output for
- * <code>out</code>
- * @return non-null; the encoded array
+ * {@code out}
+ * @return {@code non-null;} the encoded array
*/
private byte[] encode(DexFile file, String prefix, PrintWriter debugPrint,
AnnotatedOutput out, boolean consume) {
@@ -161,14 +161,14 @@
/**
* Helper for {@link #encode} to do most of the work.
*
- * @param file null-ok; file to refer to during encoding
- * @param prefix null-ok; prefix to attach to each line of output
- * @param debugPrint null-ok; if specified, an alternate output for
+ * @param file {@code null-ok;} file to refer to during encoding
+ * @param prefix {@code null-ok;} prefix to attach to each line of output
+ * @param debugPrint {@code null-ok;} if specified, an alternate output for
* annotations
- * @param out null-ok; if specified, where annotations should go
+ * @param out {@code null-ok;} if specified, where annotations should go
* @param consume whether to claim to have consumed output for
- * <code>out</code>
- * @return non-null; the encoded array
+ * {@code out}
+ * @return {@code non-null;} the encoded array
*/
private byte[] encode0(DexFile file, String prefix, PrintWriter debugPrint,
AnnotatedOutput out, boolean consume) {
diff --git a/dx/src/com/android/dx/dex/file/DexFile.java b/dx/src/com/android/dx/dex/file/DexFile.java
index 8a4075d..a829fed 100644
--- a/dx/src/com/android/dx/dex/file/DexFile.java
+++ b/dx/src/com/android/dx/dex/file/DexFile.java
@@ -38,67 +38,67 @@
import static com.android.dx.dex.file.MixedItemSection.SortType;
/**
- * Representation of an entire <code>.dex</code> (Dalvik EXecutable)
+ * Representation of an entire {@code .dex} (Dalvik EXecutable)
* file, which itself consists of a set of Dalvik classes.
*/
public final class DexFile {
- /** non-null; word data section */
+ /** {@code non-null;} word data section */
private final MixedItemSection wordData;
/**
- * non-null; type lists section. This is word data, but separating
+ * {@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}.
*/
private final MixedItemSection typeLists;
/**
- * non-null; map section. The map needs to be in a section by itself
+ * {@code non-null;} map section. The map needs to be in a section by itself
* for the self-reference mechanics to work in a reasonably
* straightforward way. See {@link MapItem#addMap} for more detail.
*/
private final MixedItemSection map;
- /** non-null; string data section */
+ /** {@code non-null;} string data section */
private final MixedItemSection stringData;
- /** non-null; string identifiers section */
+ /** {@code non-null;} string identifiers section */
private final StringIdsSection stringIds;
- /** non-null; type identifiers section */
+ /** {@code non-null;} type identifiers section */
private final TypeIdsSection typeIds;
- /** non-null; prototype identifiers section */
+ /** {@code non-null;} prototype identifiers section */
private final ProtoIdsSection protoIds;
- /** non-null; field identifiers section */
+ /** {@code non-null;} field identifiers section */
private final FieldIdsSection fieldIds;
- /** non-null; method identifiers section */
+ /** {@code non-null;} method identifiers section */
private final MethodIdsSection methodIds;
- /** non-null; class definitions section */
+ /** {@code non-null;} class definitions section */
private final ClassDefsSection classDefs;
- /** non-null; class data section */
+ /** {@code non-null;} class data section */
private final MixedItemSection classData;
- /** non-null; byte data section */
+ /** {@code non-null;} byte data section */
private final MixedItemSection byteData;
- /** non-null; file header */
+ /** {@code non-null;} file header */
private final HeaderSection header;
/**
- * non-null; array of sections in the order they will appear in the
+ * {@code non-null;} array of sections in the order they will appear in the
* final output file
*/
private final Section[] sections;
- /** >= -1; total file size or <code>-1</code> if unknown */
+ /** {@code >= -1;} total file size or {@code -1} if unknown */
private int fileSize;
- /** >= 40; maximum width of the file dump */
+ /** {@code >= 40;} maximum width of the file dump */
private int dumpWidth;
/**
@@ -137,7 +137,7 @@
* Adds a class to this instance. It is illegal to attempt to add more
* than one class with the same name.
*
- * @param clazz non-null; the class to add
+ * @param clazz {@code non-null;} the class to add
*/
public void add(ClassDefItem clazz) {
classDefs.add(clazz);
@@ -146,8 +146,8 @@
/**
* Gets the class definition with the given name, if any.
*
- * @param name non-null; the class name to look for
- * @return null-ok; the class with the given name, or <code>null</code>
+ * @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
*/
public ClassDefItem getClassOrNull(String name) {
@@ -164,8 +164,8 @@
* Writes the contents of this instance as either a binary or a
* human-readable form, or both.
*
- * @param out null-ok; where to write to
- * @param humanOut null-ok; where to write human-oriented output to
+ * @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
*/
public void writeTo(OutputStream out, Writer humanOut, boolean verbose)
@@ -183,12 +183,12 @@
}
/**
- * Returns the contents of this instance as a <code>.dex</code> file,
- * in <code>byte[]</code> form.
+ * Returns the contents of this instance as a {@code .dex} file,
+ * in {@code byte[]} form.
*
- * @param humanOut null-ok; where to write human-oriented output to
+ * @param humanOut {@code null-ok;} where to write human-oriented output to
* @param verbose whether to be verbose when writing human-oriented output
- * @return non-null; a <code>.dex</code> file for this instance
+ * @return {@code non-null;} a {@code .dex} file for this instance
*/
public byte[] toDex(Writer humanOut, boolean verbose)
throws IOException {
@@ -205,7 +205,7 @@
/**
* Sets the maximum width of the human-oriented dump of the instance.
*
- * @param dumpWidth >= 40; the width
+ * @param dumpWidth {@code >= 40;} the width
*/
public void setDumpWidth(int dumpWidth) {
if (dumpWidth < 40) {
@@ -221,7 +221,7 @@
* <p>This is package-scope in order to allow
* the {@link HeaderSection} to set itself up properly.</p>
*
- * @return >= 0; the total file size
+ * @return {@code >= 0;} the total file size
* @throws RuntimeException thrown if the file size is not yet known
*/
/*package*/ int getFileSize() {
@@ -239,7 +239,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the string data section
+ * @return {@code non-null;} the string data section
*/
/*package*/ MixedItemSection getStringData() {
return stringData;
@@ -252,7 +252,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the word data section
+ * @return {@code non-null;} the word data section
*/
/*package*/ MixedItemSection getWordData() {
return wordData;
@@ -265,7 +265,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the word data section
+ * @return {@code non-null;} the word data section
*/
/*package*/ MixedItemSection getTypeLists() {
return typeLists;
@@ -277,7 +277,7 @@
* <p>This is package-scope in order to allow the header section
* to query it.</p>
*
- * @return non-null; the map section
+ * @return {@code non-null;} the map section
*/
/*package*/ MixedItemSection getMap() {
return map;
@@ -290,7 +290,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the string identifiers section
+ * @return {@code non-null;} the string identifiers section
*/
/*package*/ StringIdsSection getStringIds() {
return stringIds;
@@ -303,7 +303,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the class definitions section
+ * @return {@code non-null;} the class definitions section
*/
/*package*/ ClassDefsSection getClassDefs() {
return classDefs;
@@ -316,7 +316,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the class data section
+ * @return {@code non-null;} the class data section
*/
/*package*/ MixedItemSection getClassData() {
return classData;
@@ -329,7 +329,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the class identifiers section
+ * @return {@code non-null;} the class identifiers section
*/
/*package*/ TypeIdsSection getTypeIds() {
return typeIds;
@@ -342,7 +342,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the prototype identifiers section
+ * @return {@code non-null;} the prototype identifiers section
*/
/*package*/ ProtoIdsSection getProtoIds() {
return protoIds;
@@ -355,7 +355,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the field identifiers section
+ * @return {@code non-null;} the field identifiers section
*/
/*package*/ FieldIdsSection getFieldIds() {
return fieldIds;
@@ -368,7 +368,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the method identifiers section
+ * @return {@code non-null;} the method identifiers section
*/
/*package*/ MethodIdsSection getMethodIds() {
return methodIds;
@@ -381,7 +381,7 @@
* the various {@link Item} instances to add items to the
* instance.</p>
*
- * @return non-null; the byte data section
+ * @return {@code non-null;} the byte data section
*/
/*package*/ MixedItemSection getByteData() {
return byteData;
@@ -394,7 +394,7 @@
* <p>This is package-scope in order to allow the header section
* to query it.</p>
*
- * @return non-null; the section
+ * @return {@code non-null;} the section
*/
/*package*/ Section getFirstDataSection() {
return wordData;
@@ -407,7 +407,7 @@
* <p>This is package-scope in order to allow the header section
* to query it.</p>
*
- * @return non-null; the section
+ * @return {@code non-null;} the section
*/
/*package*/ Section getLastDataSection() {
return map;
@@ -418,7 +418,7 @@
* instance, or do nothing if the given constant isn't the sort
* that should be interned.
*
- * @param cst non-null; constant to possibly intern
+ * @param cst {@code non-null;} constant to possibly intern
*/
/*package*/ void internIfAppropriate(Constant cst) {
if (cst instanceof CstString) {
@@ -441,13 +441,13 @@
/**
* Gets the {@link IndexedItem} corresponding to the given constant,
* if it is a constant that has such a correspondence, or return
- * <code>null</code> if it isn't such a constant. This will throw
+ * {@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 non-null; the constant to look up
- * @return null-ok; its corresponding item, if it has a corresponding
- * item, or <code>null</code> if it's not that sort of constant
+ * @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
*/
/*package*/ IndexedItem findItemOrNull(Constant cst) {
IndexedItem item;
@@ -466,12 +466,12 @@
}
/**
- * Returns the contents of this instance as a <code>.dex</code> file,
+ * 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 non-null; a <code>.dex</code> file for this instance
+ * @return {@code non-null;} a {@code .dex} file for this instance
*/
private ByteArrayAnnotatedOutput toDex0(boolean annotate,
boolean verbose) {
@@ -586,7 +586,7 @@
/**
* Generates and returns statistics for all the items in the file.
*
- * @return non-null; the statistics
+ * @return {@code non-null;} the statistics
*/
public Statistics getStatistics() {
Statistics stats = new Statistics();
@@ -599,10 +599,10 @@
}
/**
- * Calculates the signature for the <code>.dex</code> file in the
+ * Calculates the signature for the {@code .dex} file in the
* given array, and modify the array to contain it.
*
- * @param bytes non-null; the bytes of the file
+ * @param bytes {@code non-null;} the bytes of the file
*/
private static void calcSignature(byte[] bytes) {
MessageDigest md;
@@ -627,10 +627,10 @@
}
/**
- * Calculates the checksum for the <code>.dex</code> file in the
+ * Calculates the checksum for the {@code .dex} file in the
* given array, and modify the array to contain it.
*
- * @param bytes non-null; the bytes of the file
+ * @param bytes {@code non-null;} the bytes of the file
*/
private static void calcChecksum(byte[] bytes) {
Adler32 a32 = new Adler32();
diff --git a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
index 9ec72fa..c55c6f5 100644
--- a/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
+++ b/dx/src/com/android/dx/dex/file/EncodedArrayItem.java
@@ -36,11 +36,11 @@
/** the required alignment for instances of this class */
private static final int ALIGNMENT = 1;
- /** non-null; the array to represent */
+ /** {@code non-null;} the array to represent */
private final CstArray array;
/**
- * null-ok; encoded form, ready for writing to a file; set during
+ * {@code null-ok;} encoded form, ready for writing to a file; set during
* {@link #place0}
*/
private byte[] encodedForm;
@@ -48,7 +48,7 @@
/**
* Constructs an instance.
*
- * @param array non-null; array to represent
+ * @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 62a5789..146a604 100644
--- a/dx/src/com/android/dx/dex/file/EncodedField.java
+++ b/dx/src/com/android/dx/dex/file/EncodedField.java
@@ -30,13 +30,13 @@
*/
public final class EncodedField extends EncodedMember
implements Comparable<EncodedField> {
- /** non-null; constant for the field */
+ /** {@code non-null;} constant for the field */
private final CstFieldRef field;
/**
* Constructs an instance.
*
- * @param field non-null; constant for the field
+ * @param field {@code non-null;} constant for the field
* @param accessFlags access flags
*/
public EncodedField(CstFieldRef field, int accessFlags) {
@@ -122,7 +122,7 @@
/**
* Gets the constant for the field.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public CstFieldRef getRef() {
return field;
diff --git a/dx/src/com/android/dx/dex/file/EncodedMember.java b/dx/src/com/android/dx/dex/file/EncodedMember.java
index 3ae0d09..68119f3 100644
--- a/dx/src/com/android/dx/dex/file/EncodedMember.java
+++ b/dx/src/com/android/dx/dex/file/EncodedMember.java
@@ -51,14 +51,14 @@
/**
* Gets the name.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public abstract CstUtf8 getName();
/**
* Does a human-friendly dump of this instance.
*
- * @param out non-null; where to dump
+ * @param out {@code non-null;} where to dump
* @param verbose whether to be verbose with the output
*/
public abstract void debugPrint(PrintWriter out, boolean verbose);
@@ -66,20 +66,20 @@
/**
* Populates a {@link DexFile} with items from within this instance.
*
- * @param file non-null; the file to populate
+ * @param file {@code non-null;} the file to populate
*/
public abstract void addContents(DexFile file);
/**
* Encodes this instance to the given output.
*
- * @param file non-null; file this instance is part of
- * @param out non-null; where to write to
- * @param lastIndex >= 0; the previous member index value encoded, or
- * <code>0</code> if this is the first element to encode
- * @param dumpSeq >= 0; sequence number of this instance for
+ * @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
+ * {@code 0} if this is the first element to encode
+ * @param dumpSeq {@code >= 0;} sequence number of this instance for
* annotation purposes
- * @return >= 0; the member index value that was encoded
+ * @return {@code >= 0;} the member index value that was encoded
*/
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 319fbb7..dff1a07 100644
--- a/dx/src/com/android/dx/dex/file/EncodedMethod.java
+++ b/dx/src/com/android/dx/dex/file/EncodedMethod.java
@@ -32,23 +32,23 @@
*/
public final class EncodedMethod extends EncodedMember
implements Comparable<EncodedMethod> {
- /** non-null; constant for the method */
+ /** {@code non-null;} constant for the method */
private final CstMethodRef method;
/**
- * null-ok; code for the method, if the method is neither
- * <code>abstract</code> nor <code>native</code>
+ * {@code null-ok;} code for the method, if the method is neither
+ * {@code abstract} nor {@code native}
*/
private final CodeItem code;
/**
* Constructs an instance.
*
- * @param method non-null; constant for the method
+ * @param method {@code non-null;} constant for the method
* @param accessFlags access flags
- * @param code null-ok; code for the method, if it is neither
- * <code>abstract</code> nor <code>native</code>
- * @param throwsList non-null; list of possibly-thrown exceptions,
+ * @param code {@code null-ok;} code for the method, if it is neither
+ * {@code abstract} nor {@code native}
+ * @param throwsList {@code non-null;} list of possibly-thrown exceptions,
* just used in generating debugging output (listings)
*/
public EncodedMethod(CstMethodRef method, int accessFlags,
@@ -148,7 +148,7 @@
/**
* Gets the constant for the method.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public final CstMethodRef getRef() {
return method;
diff --git a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
index e6169bd..6a76ca9 100644
--- a/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
+++ b/dx/src/com/android/dx/dex/file/FieldAnnotationStruct.java
@@ -27,17 +27,17 @@
*/
public final class FieldAnnotationStruct
implements ToHuman, Comparable<FieldAnnotationStruct> {
- /** non-null; the field in question */
+ /** {@code non-null;} the field in question */
private final CstFieldRef field;
- /** non-null; the associated annotations */
+ /** {@code non-null;} the associated annotations */
private AnnotationSetItem annotations;
/**
* Constructs an instance.
*
- * @param field non-null; the field in question
- * @param annotations non-null; the associated annotations
+ * @param field {@code non-null;} the field in question
+ * @param annotations {@code non-null;} the associated annotations
*/
public FieldAnnotationStruct(CstFieldRef field,
AnnotationSetItem annotations) {
@@ -105,7 +105,7 @@
/**
* Gets the field this item is for.
*
- * @return non-null; the field
+ * @return {@code non-null;} the field
*/
public CstFieldRef getField() {
return field;
@@ -114,7 +114,7 @@
/**
* Gets the associated annotations.
*
- * @return non-null; the annotations
+ * @return {@code non-null;} the annotations
*/
public Annotations getAnnotations() {
return 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 d098d52..d6d01d5 100644
--- a/dx/src/com/android/dx/dex/file/FieldIdItem.java
+++ b/dx/src/com/android/dx/dex/file/FieldIdItem.java
@@ -25,7 +25,7 @@
/**
* Constructs an instance.
*
- * @param field non-null; the constant for the field
+ * @param field {@code non-null;} the constant for the field
*/
public FieldIdItem(CstFieldRef field) {
super(field);
@@ -49,7 +49,7 @@
/**
* Gets the field constant.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public CstFieldRef getFieldRef() {
return (CstFieldRef) getRef();
diff --git a/dx/src/com/android/dx/dex/file/FieldIdsSection.java b/dx/src/com/android/dx/dex/file/FieldIdsSection.java
index fddf55f..59ef229 100644
--- a/dx/src/com/android/dx/dex/file/FieldIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/FieldIdsSection.java
@@ -25,11 +25,11 @@
import java.util.TreeMap;
/**
- * Field refs list section of a <code>.dex</code> file.
+ * Field refs list section of a {@code .dex} file.
*/
public final class FieldIdsSection extends MemberIdsSection {
/**
- * non-null; map from field constants to {@link
+ * {@code non-null;} map from field constants to {@link
* FieldIdItem} instances
*/
private final TreeMap<CstFieldRef, FieldIdItem> fieldIds;
@@ -37,7 +37,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public FieldIdsSection(DexFile file) {
super("field_ids", file);
@@ -72,7 +72,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -92,8 +92,8 @@
/**
* Interns an element into this instance.
*
- * @param field non-null; the reference to intern
- * @return non-null; the interned reference
+ * @param field {@code non-null;} the reference to intern
+ * @return {@code non-null;} the interned reference
*/
public FieldIdItem intern(CstFieldRef field) {
if (field == null) {
@@ -116,8 +116,8 @@
* Gets the index of the given reference, which must have been added
* to this instance.
*
- * @param ref non-null; the reference to look up
- * @return >= 0; the reference's index
+ * @param ref {@code non-null;} the reference to look up
+ * @return {@code >= 0;} the reference's index
*/
public int indexOf(CstFieldRef ref) {
if (ref == null) {
diff --git a/dx/src/com/android/dx/dex/file/HeaderItem.java b/dx/src/com/android/dx/dex/file/HeaderItem.java
index 55c1f1c..6593859 100644
--- a/dx/src/com/android/dx/dex/file/HeaderItem.java
+++ b/dx/src/com/android/dx/dex/file/HeaderItem.java
@@ -21,11 +21,11 @@
import com.android.dx.util.Hex;
/**
- * File header section of a <code>.dex</code> file.
+ * File header section of a {@code .dex} file.
*/
public final class HeaderItem extends IndexedItem {
/**
- * non-null; the file format magic number, represented as the
+ * {@code non-null;} the file format magic number, represented as the
* low-order bytes of a string
*/
private static final String MAGIC = "dex\n035\0";
diff --git a/dx/src/com/android/dx/dex/file/HeaderSection.java b/dx/src/com/android/dx/dex/file/HeaderSection.java
index 9022e0f..5bc6278 100644
--- a/dx/src/com/android/dx/dex/file/HeaderSection.java
+++ b/dx/src/com/android/dx/dex/file/HeaderSection.java
@@ -23,16 +23,16 @@
import java.util.List;
/**
- * File header section of a <code>.dex</code> file.
+ * File header section of a {@code .dex} file.
*/
public final class HeaderSection extends UniformItemSection {
- /** non-null; the list of the one item in the section */
+ /** {@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 non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public HeaderSection(DexFile file) {
super(null, file, 4);
diff --git a/dx/src/com/android/dx/dex/file/IdItem.java b/dx/src/com/android/dx/dex/file/IdItem.java
index 8342514..5d7c9e3 100644
--- a/dx/src/com/android/dx/dex/file/IdItem.java
+++ b/dx/src/com/android/dx/dex/file/IdItem.java
@@ -23,7 +23,7 @@
*/
public abstract class IdItem extends IndexedItem {
/**
- * non-null; the type constant for the defining class of
+ * {@code non-null;} the type constant for the defining class of
* the reference
*/
private final CstType type;
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
*
- * @param type non-null; the type constant for the defining
+ * @param type {@code non-null;} the type constant for the defining
* class of the reference
*/
public IdItem(CstType type) {
@@ -53,7 +53,7 @@
* Gets the type constant for the defining class of the
* reference.
*
- * @return non-null; the type constant
+ * @return {@code non-null;} the type constant
*/
public final CstType getDefiningClass() {
return type;
diff --git a/dx/src/com/android/dx/dex/file/IndexedItem.java b/dx/src/com/android/dx/dex/file/IndexedItem.java
index 9bf7fd2..32d69ea 100644
--- a/dx/src/com/android/dx/dex/file/IndexedItem.java
+++ b/dx/src/com/android/dx/dex/file/IndexedItem.java
@@ -20,7 +20,7 @@
* An item in a Dalvik file which is referenced by index.
*/
public abstract class IndexedItem extends Item {
- /** >= -1; assigned index of the item, or <code>-1</code> if not
+ /** {@code >= -1;} assigned index of the item, or {@code -1} if not
* yet assigned */
private int index;
@@ -34,7 +34,7 @@
/**
* Gets whether or not this instance has been assigned an index.
*
- * @return <code>true</code> iff this instance has been assigned an index
+ * @return {@code true} iff this instance has been assigned an index
*/
public final boolean hasIndex() {
return (index >= 0);
@@ -43,7 +43,7 @@
/**
* Gets the item index.
*
- * @return >= 0; the index
+ * @return {@code >= 0;} the index
* @throws RuntimeException thrown if the item index is not yet assigned
*/
public final int getIndex() {
@@ -56,10 +56,10 @@
/**
* Sets the item index. This method may only ever be called once
- * per instance, and this will throw a <code>RuntimeException</code> if
+ * per instance, and this will throw a {@code RuntimeException} if
* called a second (or subsequent) time.
*
- * @param index >= 0; the item index
+ * @param index {@code >= 0;} the item index
*/
public final void setIndex(int index) {
if (this.index != -1) {
@@ -73,7 +73,7 @@
* Gets the index of this item as a string, suitable for including in
* annotations.
*
- * @return non-null; the index string
+ * @return {@code non-null;} the index string
*/
public final String indexString() {
return '[' + Integer.toHexString(index) + ']';
diff --git a/dx/src/com/android/dx/dex/file/Item.java b/dx/src/com/android/dx/dex/file/Item.java
index 3708d45..057f218 100644
--- a/dx/src/com/android/dx/dex/file/Item.java
+++ b/dx/src/com/android/dx/dex/file/Item.java
@@ -33,7 +33,7 @@
/**
* Returns the item type for this instance.
*
- * @return non-null; the item type
+ * @return {@code non-null;} the item type
*/
public abstract ItemType itemType();
@@ -41,7 +41,7 @@
* Returns the human name for the particular type of item this
* instance is.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public final String typeName() {
return itemType().toHuman();
@@ -50,7 +50,7 @@
/**
* Gets the size of this instance when written, in bytes.
*
- * @return >= 0; the write size
+ * @return {@code >= 0;} the write size
*/
public abstract int writeSize();
@@ -62,7 +62,7 @@
* <p><b>Note:</b> Subclasses must override this to do something
* appropriate.</p>
*
- * @param file non-null; the file to populate
+ * @param file {@code non-null;} the file to populate
*/
public abstract void addContents(DexFile file);
@@ -73,8 +73,8 @@
* note the written offset and will also throw an exception if this
* instance has already been written.
*
- * @param file non-null; the file to use for reference
- * @param out non-null; where to write to
+ * @param file {@code non-null;} the file to use for reference
+ * @param out {@code non-null;} where to write to
*/
public abstract void writeTo(DexFile file, AnnotatedOutput out);
}
diff --git a/dx/src/com/android/dx/dex/file/ItemType.java b/dx/src/com/android/dx/dex/file/ItemType.java
index ffa6573..83843b7 100644
--- a/dx/src/com/android/dx/dex/file/ItemType.java
+++ b/dx/src/com/android/dx/dex/file/ItemType.java
@@ -48,17 +48,17 @@
/** value when represented in a {@link MapItem} */
private final int mapValue;
- /** non-null; name of the type */
+ /** {@code non-null;} name of the type */
private final String typeName;
- /** non-null; the short human name */
+ /** {@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 non-null; name of the type
+ * @param typeName {@code non-null;} name of the type
*/
private ItemType(int mapValue, String typeName) {
this.mapValue = mapValue;
@@ -84,7 +84,7 @@
/**
* Gets the type name.
*
- * @return non-null; the type name
+ * @return {@code non-null;} the type name
*/
public String getTypeName() {
return typeName;
diff --git a/dx/src/com/android/dx/dex/file/MapItem.java b/dx/src/com/android/dx/dex/file/MapItem.java
index 5e7465c..c728dd7 100644
--- a/dx/src/com/android/dx/dex/file/MapItem.java
+++ b/dx/src/com/android/dx/dex/file/MapItem.java
@@ -28,29 +28,29 @@
/** file alignment of this class, in bytes */
private static final int ALIGNMENT = 4;
- /** write size of this class, in bytes: three <code>uint</code>s */
+ /** write size of this class, in bytes: three {@code uint}s */
private static final int WRITE_SIZE = (4 * 3);
- /** non-null; item type this instance covers */
+ /** {@code non-null;} item type this instance covers */
private final ItemType type;
- /** non-null; section this instance covers */
+ /** {@code non-null;} section this instance covers */
private final Section section;
/**
- * null-ok; first item covered or <code>null</code> if this is
+ * {@code null-ok;} first item covered or {@code null} if this is
* a self-reference
*/
private final Item firstItem;
/**
- * null-ok; last item covered or <code>null</code> if this is
+ * {@code null-ok;} last item covered or {@code null} if this is
* a self-reference
*/
private final Item lastItem;
/**
- * > 0; count of items covered; <code>1</code> if this
+ * {@code > 0;} count of items covered; {@code 1} if this
* is a self-reference
*/
private final int itemCount;
@@ -60,8 +60,8 @@
* the contents of the given array of sections, adding it to the
* given map section.
*
- * @param sections non-null; the sections
- * @param mapSection non-null; the section that the resulting map
+ * @param sections {@code non-null;} the sections
+ * @param mapSection {@code non-null;} the section that the resulting map
* should be added to; it should be empty on entry to this method
*/
public static void addMap(Section[] sections,
@@ -115,11 +115,11 @@
/**
* Constructs an instance.
*
- * @param type non-null; item type this instance covers
- * @param section non-null; section this instance covers
- * @param firstItem non-null; first item covered
- * @param lastItem non-null; last item covered
- * @param itemCount > 0; count of items covered
+ * @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
+ * @param lastItem {@code non-null;} last item covered
+ * @param itemCount {@code > 0;} count of items covered
*/
private MapItem(ItemType type, Section section, Item firstItem,
Item lastItem, int itemCount) {
@@ -154,9 +154,9 @@
/**
* Constructs a self-referential instance. This instance is meant to
- * represent the section containing the <code>map_list</code>.
+ * represent the section containing the {@code map_list}.
*
- * @param section non-null; section this instance covers
+ * @param section {@code non-null;} section this instance covers
*/
private MapItem(Section section) {
super(ALIGNMENT, WRITE_SIZE);
diff --git a/dx/src/com/android/dx/dex/file/MemberIdItem.java b/dx/src/com/android/dx/dex/file/MemberIdItem.java
index d437152..574d413 100644
--- a/dx/src/com/android/dx/dex/file/MemberIdItem.java
+++ b/dx/src/com/android/dx/dex/file/MemberIdItem.java
@@ -29,13 +29,13 @@
/** size of instances when written out to a file, in bytes */
public static final int WRITE_SIZE = 8;
- /** non-null; the constant for the member */
+ /** {@code non-null;} the constant for the member */
private final CstMemberRef cst;
/**
* Constructs an instance.
*
- * @param cst non-null; the constant for the member
+ * @param cst {@code non-null;} the constant for the member
*/
public MemberIdItem(CstMemberRef cst) {
super(cst.getDefiningClass());
@@ -86,7 +86,7 @@
* 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 non-null; the file being written
+ * @param file {@code non-null;} the file being written
* @return the index in question
*/
protected abstract int getTypoidIdx(DexFile file);
@@ -96,14 +96,14 @@
* this item, for listing-generating purposes. Subclasses must override
* this.
*
- * @return non-null; the name in question
+ * @return {@code non-null;} the name in question
*/
protected abstract String getTypoidName();
/**
* Gets the member constant.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public final CstMemberRef getRef() {
return cst;
diff --git a/dx/src/com/android/dx/dex/file/MemberIdsSection.java b/dx/src/com/android/dx/dex/file/MemberIdsSection.java
index 885b559..20b1605 100644
--- a/dx/src/com/android/dx/dex/file/MemberIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/MemberIdsSection.java
@@ -17,15 +17,15 @@
package com.android.dx.dex.file;
/**
- * Member (field or method) refs list section of a <code>.dex</code> file.
+ * Member (field or method) refs list section of a {@code .dex} file.
*/
public abstract class MemberIdsSection extends UniformItemSection {
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param name null-ok; the name of this instance, for annotation
+ * @param name {@code null-ok;} the name of this instance, for annotation
* purposes
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public MemberIdsSection(String name, DexFile file) {
super(name, file, 4);
diff --git a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
index 175c1d2..3c254a1 100644
--- a/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
+++ b/dx/src/com/android/dx/dex/file/MethodAnnotationStruct.java
@@ -27,17 +27,17 @@
*/
public final class MethodAnnotationStruct
implements ToHuman, Comparable<MethodAnnotationStruct> {
- /** non-null; the method in question */
+ /** {@code non-null;} the method in question */
private final CstMethodRef method;
- /** non-null; the associated annotations */
+ /** {@code non-null;} the associated annotations */
private AnnotationSetItem annotations;
/**
* Constructs an instance.
*
- * @param method non-null; the method in question
- * @param annotations non-null; the associated annotations
+ * @param method {@code non-null;} the method in question
+ * @param annotations {@code non-null;} the associated annotations
*/
public MethodAnnotationStruct(CstMethodRef method,
AnnotationSetItem annotations) {
@@ -105,7 +105,7 @@
/**
* Gets the method this item is for.
*
- * @return non-null; the method
+ * @return {@code non-null;} the method
*/
public CstMethodRef getMethod() {
return method;
@@ -114,7 +114,7 @@
/**
* Gets the associated annotations.
*
- * @return non-null; the annotations
+ * @return {@code non-null;} the annotations
*/
public Annotations getAnnotations() {
return 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 5d78e96..bbd6c93 100644
--- a/dx/src/com/android/dx/dex/file/MethodIdItem.java
+++ b/dx/src/com/android/dx/dex/file/MethodIdItem.java
@@ -25,7 +25,7 @@
/**
* Constructs an instance.
*
- * @param method non-null; the constant for the method
+ * @param method {@code non-null;} the constant for the method
*/
public MethodIdItem(CstBaseMethodRef method) {
super(method);
@@ -49,7 +49,7 @@
/**
* Gets the method constant.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public CstBaseMethodRef getMethodRef() {
return (CstBaseMethodRef) getRef();
diff --git a/dx/src/com/android/dx/dex/file/MethodIdsSection.java b/dx/src/com/android/dx/dex/file/MethodIdsSection.java
index 6ba7cac..f3e7dee 100644
--- a/dx/src/com/android/dx/dex/file/MethodIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/MethodIdsSection.java
@@ -25,11 +25,11 @@
import java.util.TreeMap;
/**
- * Method refs list section of a <code>.dex</code> file.
+ * Method refs list section of a {@code .dex} file.
*/
public final class MethodIdsSection extends MemberIdsSection {
/**
- * non-null; map from method constants to {@link
+ * {@code non-null;} map from method constants to {@link
* MethodIdItem} instances
*/
private final TreeMap<CstBaseMethodRef, MethodIdItem> methodIds;
@@ -37,7 +37,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public MethodIdsSection(DexFile file) {
super("method_ids", file);
@@ -72,7 +72,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -92,8 +92,8 @@
/**
* Interns an element into this instance.
*
- * @param method non-null; the reference to intern
- * @return non-null; the interned reference
+ * @param method {@code non-null;} the reference to intern
+ * @return {@code non-null;} the interned reference
*/
public MethodIdItem intern(CstBaseMethodRef method) {
if (method == null) {
@@ -116,8 +116,8 @@
* Gets the index of the given reference, which must have been added
* to this instance.
*
- * @param ref non-null; the reference to look up
- * @return >= 0; the reference's index
+ * @param ref {@code non-null;} the reference to look up
+ * @return {@code >= 0;} the reference's index
*/
public int indexOf(CstBaseMethodRef ref) {
if (ref == null) {
diff --git a/dx/src/com/android/dx/dex/file/MixedItemSection.java b/dx/src/com/android/dx/dex/file/MixedItemSection.java
index f03a9a3..0929fe7 100644
--- a/dx/src/com/android/dx/dex/file/MixedItemSection.java
+++ b/dx/src/com/android/dx/dex/file/MixedItemSection.java
@@ -31,7 +31,7 @@
import java.util.TreeMap;
/**
- * A section of a <code>.dex</code> file which consists of a sequence of
+ * 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.
*
@@ -50,7 +50,7 @@
INSTANCE;
};
- /** non-null; sorter which sorts instances by type */
+ /** {@code non-null;} sorter which sorts instances by type */
private static final Comparator<OffsettedItem> TYPE_SORTER =
new Comparator<OffsettedItem>() {
public int compare(OffsettedItem item1, OffsettedItem item2) {
@@ -60,17 +60,17 @@
}
};
- /** non-null; the items in this part */
+ /** {@code non-null;} the items in this part */
private final ArrayList<OffsettedItem> items;
- /** non-null; items that have been explicitly interned */
+ /** {@code non-null;} items that have been explicitly interned */
private final HashMap<OffsettedItem, OffsettedItem> interns;
- /** non-null; how to sort the items */
+ /** {@code non-null;} how to sort the items */
private final SortType sort;
/**
- * >= -1; the current size of this part, in bytes, or <code>-1</code>
+ * {@code >= -1;} the current size of this part, in bytes, or {@code -1}
* if not yet calculated
*/
private int writeSize;
@@ -78,10 +78,10 @@
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param name null-ok; the name of this instance, for annotation
+ * @param name {@code null-ok;} the name of this instance, for annotation
* purposes
- * @param file non-null; file that this instance is part of
- * @param alignment > 0; alignment requirement for the final output;
+ * @param file {@code non-null;} file that this instance is part of
+ * @param alignment {@code > 0;} alignment requirement for the final output;
* must be a power of 2
* @param sort how the items should be sorted in the final output
*/
@@ -118,7 +118,7 @@
/**
* Gets the size of this instance, in items.
*
- * @return >= 0; the size
+ * @return {@code >= 0;} the size
*/
public int size() {
return items.size();
@@ -127,7 +127,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -164,7 +164,7 @@
* same item to more than one instance, nor to add the same items
* multiple times to a single instance.
*
- * @param item non-null; the item to add
+ * @param item {@code non-null;} the item to add
*/
public void add(OffsettedItem item) {
throwIfPrepared();
@@ -187,8 +187,8 @@
* (which may not be the one passed in). This will add the item if no
* equal item has been added.
*
- * @param item non-null; the item to intern
- * @return non-null; the equivalent interned instance
+ * @param item {@code non-null;} the item to intern
+ * @return {@code non-null;} the equivalent interned instance
*/
public <T extends OffsettedItem> T intern(T item) {
throwIfPrepared();
@@ -207,8 +207,8 @@
/**
* Gets an item which was previously interned.
*
- * @param item non-null; the item to look for
- * @return non-null; the equivalent already-interned instance
+ * @param item {@code non-null;} the item to look for
+ * @return {@code non-null;} the equivalent already-interned instance
*/
public <T extends OffsettedItem> T get(T item) {
throwIfNotPrepared();
@@ -227,9 +227,9 @@
* 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 non-null; where to write to
- * @param itemType non-null; the item type of interest
- * @param intro non-null; the introductory string for non-empty indices
+ * @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
*/
public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType,
String intro) {
@@ -285,7 +285,7 @@
/**
* Places all the items in this instance at particular offsets. This
* will call {@link OffsettedItem#place} on each item. If an item
- * does not know its write size before the call to <code>place</code>,
+ * does not know its write size before the call to {@code place},
* it is that call which is responsible for setting the write size.
* This method may only be called once per instance; subsequent calls
* will throw an exception.
diff --git a/dx/src/com/android/dx/dex/file/OffsettedItem.java b/dx/src/com/android/dx/dex/file/OffsettedItem.java
index 030c370..c8e2d74 100644
--- a/dx/src/com/android/dx/dex/file/OffsettedItem.java
+++ b/dx/src/com/android/dx/dex/file/OffsettedItem.java
@@ -24,32 +24,32 @@
*/
public abstract class OffsettedItem extends Item
implements Comparable<OffsettedItem> {
- /** > 0; alignment requirement */
+ /** {@code > 0;} alignment requirement */
private final int alignment;
- /** >= -1; the size of this instance when written, in bytes, or
- * <code>-1</code> if not yet known */
+ /** {@code >= -1;} the size of this instance when written, in bytes, or
+ * {@code -1} if not yet known */
private int writeSize;
/**
- * null-ok; section the item was added to, or <code>null</code> if
+ * {@code null-ok;} section the item was added to, or {@code null} if
* not yet added
*/
private Section addedTo;
/**
- * >= -1; assigned offset of the item from the start of its section,
- * or <code>-1</code> if not yet assigned
+ * {@code >= -1;} assigned offset of the item from the start of its section,
+ * or {@code -1} if not yet assigned
*/
private int offset;
/**
- * Gets the absolute offset of the given item, returning <code>0</code>
- * if handed <code>null</code>.
+ * Gets the absolute offset of the given item, returning {@code 0}
+ * if handed {@code null}.
*
- * @param item null-ok; the item in question
- * @return >= 0; the item's absolute offset, or <code>0</code>
- * if <code>item == null</code>
+ * @param item {@code null-ok;} the item in question
+ * @return {@code >= 0;} the item's absolute offset, or {@code 0}
+ * if {@code item == null}
*/
public static int getAbsoluteOffsetOr0(OffsettedItem item) {
if (item == null) {
@@ -62,10 +62,10 @@
/**
* Constructs an instance. The offset is initially unassigned.
*
- * @param alignment > 0; output alignment requirement; must be a
+ * @param alignment {@code > 0;} output alignment requirement; must be a
* power of 2
- * @param writeSize >= -1; the size of this instance when written,
- * in bytes, or <code>-1</code> if not immediately known
+ * @param writeSize {@code >= -1;} the size of this instance when written,
+ * in bytes, or {@code -1} if not immediately known
*/
public OffsettedItem(int alignment, int writeSize) {
Section.validateAlignment(alignment);
@@ -131,7 +131,7 @@
* per instance, and only if the size was unknown upon instance
* creation.
*
- * @param writeSize > 0; the write size, in bytes
+ * @param writeSize {@code > 0;} the write size, in bytes
*/
public final void setWriteSize(int writeSize) {
if (writeSize < 0) {
@@ -182,7 +182,7 @@
* Gets the relative item offset. The offset is from the start of
* the section which the instance was written to.
*
- * @return >= 0; the offset
+ * @return {@code >= 0;} the offset
* @throws RuntimeException thrown if the offset is not yet known
*/
public final int getRelativeOffset() {
@@ -197,7 +197,7 @@
* Gets the absolute item offset. The offset is from the start of
* the file which the instance was written to.
*
- * @return >= 0; the offset
+ * @return {@code >= 0;} the offset
* @throws RuntimeException thrown if the offset is not yet known
*/
public final int getAbsoluteOffset() {
@@ -213,10 +213,11 @@
* the given offset. It is only valid to call this method once per
* instance.
*
- * @param addedTo non-null; the section this instance has been added to
- * @param offset >= 0; the desired offset from the start of the
+ * @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
* section where this instance was placed
- * @return >= 0; the offset that this instance should be placed at
+ * @return {@code >= 0;} the offset that this instance should be placed at
* in order to meet its alignment constraint
*/
public final int place(Section addedTo, int offset) {
@@ -247,7 +248,7 @@
* Gets the alignment requirement of this instance. An instance should
* only be written when so aligned.
*
- * @return > 0; the alignment requirement; must be a power of 2
+ * @return {@code > 0;} the alignment requirement; must be a power of 2
*/
public final int getAlignment() {
return alignment;
@@ -257,7 +258,7 @@
* Gets the absolute offset of this item as a string, suitable for
* including in annotations.
*
- * @return non-null; the offset string
+ * @return {@code non-null;} the offset string
*/
public final String offsetString() {
return '[' + Integer.toHexString(getAbsoluteOffset()) + ']';
@@ -266,7 +267,7 @@
/**
* Gets a short human-readable string representing this instance.
*
- * @return non-null; the human form
+ * @return {@code non-null;} the human form
*/
public abstract String toHuman();
@@ -277,8 +278,8 @@
* class needs to actually sort, then it should override this
* method.
*
- * @param other non-null; instance to compare to
- * @return <code>-1</code>, <code>0</code>, or <code>1</code>, depending
+ * @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
*/
protected int compareTo0(OffsettedItem other) {
@@ -293,8 +294,8 @@
* know its write size up-front, then this method is responsible
* for setting it.
*
- * @param addedTo non-null; the section this instance has been added to
- * @param offset >= 0; the offset from the start of the
+ * @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
*/
protected void place0(Section addedTo, int offset) {
@@ -306,8 +307,8 @@
* the given data section. This is called by {@link #writeTo},
* which will have taken care of ensuring alignment.
*
- * @param file non-null; the file to use for reference
- * @param out non-null; where to write to
+ * @param file {@code non-null;} the file to use for reference
+ * @param out {@code non-null;} where to write to
*/
protected abstract void writeTo0(DexFile file, AnnotatedOutput out);
}
diff --git a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
index 0c2d286..46d0450 100644
--- a/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
+++ b/dx/src/com/android/dx/dex/file/ParameterAnnotationStruct.java
@@ -30,20 +30,20 @@
*/
public final class ParameterAnnotationStruct
implements ToHuman, Comparable<ParameterAnnotationStruct> {
- /** non-null; the method in question */
+ /** {@code non-null;} the method in question */
private final CstMethodRef method;
- /** non-null; the associated annotations list */
+ /** {@code non-null;} the associated annotations list */
private final AnnotationsList annotationsList;
- /** non-null; the associated annotations list, as an item */
+ /** {@code non-null;} the associated annotations list, as an item */
private final UniformListItem<AnnotationSetRefItem> annotationsItem;
/**
* Constructs an instance.
*
- * @param method non-null; the method in question
- * @param annotationsList non-null; the associated annotations list
+ * @param method {@code non-null;} the method in question
+ * @param annotationsList {@code non-null;} the associated annotations list
*/
public ParameterAnnotationStruct(CstMethodRef method,
AnnotationsList annotationsList) {
@@ -144,7 +144,7 @@
/**
* Gets the method this item is for.
*
- * @return non-null; the method
+ * @return {@code non-null;} the method
*/
public CstMethodRef getMethod() {
return method;
@@ -153,7 +153,7 @@
/**
* Gets the associated annotations list.
*
- * @return non-null; the annotations list
+ * @return {@code non-null;} the annotations list
*/
public AnnotationsList getAnnotationsList() {
return annotationsList;
diff --git a/dx/src/com/android/dx/dex/file/ProtoIdItem.java b/dx/src/com/android/dx/dex/file/ProtoIdItem.java
index a144c30..afc227c 100644
--- a/dx/src/com/android/dx/dex/file/ProtoIdItem.java
+++ b/dx/src/com/android/dx/dex/file/ProtoIdItem.java
@@ -31,14 +31,14 @@
/** size of instances when written out to a file, in bytes */
public static final int WRITE_SIZE = 12;
- /** non-null; the wrapped prototype */
+ /** {@code non-null;} the wrapped prototype */
private final Prototype prototype;
- /** non-null; the short-form of the prototype */
+ /** {@code non-null;} the short-form of the prototype */
private final CstUtf8 shortForm;
/**
- * null-ok; the list of parameter types or <code>null</code> if this
+ * {@code null-ok;} the list of parameter types or {@code null} if this
* prototype has no parameters
*/
private TypeListItem parameterTypes;
@@ -46,7 +46,7 @@
/**
* Constructs an instance.
*
- * @param prototype non-null; the constant for the prototype
+ * @param prototype {@code non-null;} the constant for the prototype
*/
public ProtoIdItem(Prototype prototype) {
if (prototype == null) {
@@ -64,8 +64,8 @@
/**
* Creates the short-form of the given prototype.
*
- * @param prototype non-null; the prototype
- * @return non-null; the short form
+ * @param prototype {@code non-null;} the prototype
+ * @return {@code non-null;} the short form
*/
private static CstUtf8 makeShortForm(Prototype prototype) {
StdTypeList parameters = prototype.getParameterTypes();
@@ -84,7 +84,7 @@
/**
* Gets the short-form character for the given type.
*
- * @param type non-null; the type
+ * @param type {@code non-null;} the type
* @return the corresponding short-form character
*/
private static char shortFormCharFor(Type type) {
diff --git a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
index 852ab9d..8a95434 100644
--- a/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/ProtoIdsSection.java
@@ -26,18 +26,18 @@
/**
* Proto (method prototype) identifiers list section of a
- * <code>.dex</code> file.
+ * {@code .dex} file.
*/
public final class ProtoIdsSection extends UniformItemSection {
/**
- * non-null; map from method prototypes to {@link ProtoIdItem} instances
+ * {@code non-null;} map from method prototypes to {@link ProtoIdItem} instances
*/
private final TreeMap<Prototype, ProtoIdItem> protoIds;
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public ProtoIdsSection(DexFile file) {
super("proto_ids", file, 4);
@@ -60,7 +60,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -84,8 +84,8 @@
/**
* Interns an element into this instance.
*
- * @param prototype non-null; the prototype to intern
- * @return non-null; the interned reference
+ * @param prototype {@code non-null;} the prototype to intern
+ * @return {@code non-null;} the interned reference
*/
public ProtoIdItem intern(Prototype prototype) {
if (prototype == null) {
@@ -108,8 +108,8 @@
* Gets the index of the given prototype, which must have
* been added to this instance.
*
- * @param prototype non-null; the prototype to look up
- * @return >= 0; the reference's index
+ * @param prototype {@code non-null;} the prototype to look up
+ * @return {@code >= 0;} the reference's index
*/
public int indexOf(Prototype prototype) {
if (prototype == null) {
diff --git a/dx/src/com/android/dx/dex/file/Section.java b/dx/src/com/android/dx/dex/file/Section.java
index 9f7657c..f5b43af 100644
--- a/dx/src/com/android/dx/dex/file/Section.java
+++ b/dx/src/com/android/dx/dex/file/Section.java
@@ -21,22 +21,22 @@
import java.util.Collection;
/**
- * A section of a <code>.dex</code> file. Each section consists of a list
+ * A section of a {@code .dex} file. Each section consists of a list
* of items of some sort or other.
*/
public abstract class Section {
- /** null-ok; name of this part, for annotation purposes */
+ /** {@code null-ok;} name of this part, for annotation purposes */
private final String name;
- /** non-null; file that this instance is part of */
+ /** {@code non-null;} file that this instance is part of */
private final DexFile file;
- /** > 0; alignment requirement for the final output;
+ /** {@code > 0;} alignment requirement for the final output;
* must be a power of 2 */
private final int alignment;
- /** >= -1; offset from the start of the file to this part, or
- * <code>-1</code> if not yet known */
+ /** {@code >= -1;} offset from the start of the file to this part, or
+ * {@code -1} if not yet known */
private int fileOffset;
/** whether {@link #prepare} has been called successfully on this
@@ -47,7 +47,7 @@
* Validates an alignment.
*
* @param alignment the alignment
- * @throws IllegalArgumentException thrown if <code>alignment</code>
+ * @throws IllegalArgumentException thrown if {@code alignment}
* isn't a positive power of 2
*/
public static void validateAlignment(int alignment) {
@@ -60,10 +60,10 @@
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param name null-ok; the name of this instance, for annotation
+ * @param name {@code null-ok;} the name of this instance, for annotation
* purposes
- * @param file non-null; file that this instance is part of
- * @param alignment > 0; alignment requirement for the final output;
+ * @param file {@code non-null;} file that this instance is part of
+ * @param alignment {@code > 0;} alignment requirement for the final output;
* must be a power of 2
*/
public Section(String name, DexFile file, int alignment) {
@@ -83,7 +83,7 @@
/**
* Gets the file that this instance is part of.
*
- * @return non-null; the file
+ * @return {@code non-null;} the file
*/
public final DexFile getFile() {
return file;
@@ -92,7 +92,7 @@
/**
* Gets the alignment for this instance's final output.
*
- * @return > 0; the alignment
+ * @return {@code > 0;} the alignment
*/
public final int getAlignment() {
return alignment;
@@ -102,7 +102,7 @@
* Gets the offset from the start of the file to this part. This
* throws an exception if the offset has not yet been set.
*
- * @return >= 0; the file offset
+ * @return {@code >= 0;} the file offset
*/
public final int getFileOffset() {
if (fileOffset < 0) {
@@ -116,9 +116,9 @@
* Sets the file offset. It is only valid to call this method once
* once per instance.
*
- * @param fileOffset >= 0; the desired offset from the start of the
+ * @param fileOffset {@code >= 0;} the desired offset from the start of the
* file where this for this instance
- * @return >= 0; the offset that this instance should be placed at
+ * @return {@code >= 0;} the offset that this instance should be placed at
* in order to meet its alignment constraint
*/
public final int setFileOffset(int fileOffset) {
@@ -141,7 +141,7 @@
/**
* Writes this instance to the given raw data object.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
*/
public final void writeTo(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -174,8 +174,8 @@
* once this instance has been assigned a file offset (via {@link
* #setFileOffset}).
*
- * @param relative >= 0; the relative offset
- * @return >= 0; the corresponding absolute file offset
+ * @param relative {@code >= 0;} the relative offset
+ * @return {@code >= 0;} the corresponding absolute file offset
*/
public final int getAbsoluteOffset(int relative) {
if (relative < 0) {
@@ -198,8 +198,8 @@
* <p><b>Note:</b> Subclasses must implement this as appropriate for
* their contents.</p>
*
- * @param item non-null; the item in question
- * @return >= 0; the item's absolute file offset
+ * @param item {@code non-null;} the item in question
+ * @return {@code >= 0;} the item's absolute file offset
*/
public abstract int getAbsoluteItemOffset(Item item);
@@ -219,7 +219,7 @@
* Gets the collection of all the items in this section.
* It is not valid to attempt to change the returned list.
*
- * @return non-null; the items
+ * @return {@code non-null;} the items
*/
public abstract Collection<? extends Item> items();
@@ -231,7 +231,7 @@
/**
* Gets the size of this instance when output, in bytes.
*
- * @return >= 0; the size of this instance, in bytes
+ * @return {@code >= 0;} the size of this instance, in bytes
*/
public abstract int writeSize();
@@ -258,7 +258,7 @@
/**
* Aligns the output of the given data to the alignment of this instance.
*
- * @param out non-null; the output to align
+ * @param out {@code non-null;} the output to align
*/
protected final void align(AnnotatedOutput out) {
out.alignTo(alignment);
@@ -267,19 +267,19 @@
/**
* Writes this instance to the given raw data object. This gets
* called by {@link #writeTo} after aligning the cursor of
- * <code>out</code> and verifying that either the assigned file
- * offset matches the actual cursor <code>out</code> or that the
+ * {@code out} and verifying that either the assigned file
+ * 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</code>'s cursor.
+ * assigned to {@code out}'s cursor.
*
- * @param out non-null; where to write to
+ * @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 null-ok; name of this part, for annotation purposes
+ * @return {@code null-ok;} name of this part, for annotation purposes
*/
protected final String getName() {
return name;
diff --git a/dx/src/com/android/dx/dex/file/Statistics.java b/dx/src/com/android/dx/dex/file/Statistics.java
index b11ab6e..9a2efb3 100644
--- a/dx/src/com/android/dx/dex/file/Statistics.java
+++ b/dx/src/com/android/dx/dex/file/Statistics.java
@@ -26,7 +26,7 @@
* Statistics about the contents of a file.
*/
public final class Statistics {
- /** non-null; data about each type of item */
+ /** {@code non-null;} data about each type of item */
private final HashMap<String, Data> dataMap;
/**
@@ -39,7 +39,7 @@
/**
* Adds the given item to the statistics.
*
- * @param item non-null; the item to add
+ * @param item {@code non-null;} the item to add
*/
public void add(Item item) {
String typeName = item.typeName();
@@ -55,7 +55,7 @@
/**
* Adds the given list of items to the statistics.
*
- * @param list non-null; the list of items to add
+ * @param list {@code non-null;} the list of items to add
*/
public void addAll(Section list) {
Collection<? extends Item> items = list.items();
@@ -67,7 +67,7 @@
/**
* Writes the statistics as an annotation.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
*/
public final void writeAnnotation(AnnotatedOutput out) {
if (dataMap.size() == 0) {
@@ -109,26 +109,26 @@
* Statistical data about a particular class.
*/
private static class Data {
- /** non-null; name to use as a label */
+ /** {@code non-null;} name to use as a label */
private final String name;
- /** >= 0; number of instances */
+ /** {@code >= 0;} number of instances */
private int count;
- /** >= 0; total size of instances in bytes */
+ /** {@code >= 0;} total size of instances in bytes */
private int totalSize;
- /** >= 0; largest size of any individual item */
+ /** {@code >= 0;} largest size of any individual item */
private int largestSize;
- /** >= 0; smallest size of any individual item */
+ /** {@code >= 0;} smallest size of any individual item */
private int smallestSize;
/**
* Constructs an instance for the given item.
*
- * @param item non-null; item in question
- * @param name non-null; type name to use
+ * @param item {@code non-null;} item in question
+ * @param name {@code non-null;} type name to use
*/
public Data(Item item, String name) {
int size = item.writeSize();
@@ -143,7 +143,7 @@
/**
* Incorporates a new item. This assumes the type name matches.
*
- * @param item non-null; item to incorporate
+ * @param item {@code non-null;} item to incorporate
*/
public void add(Item item) {
int size = item.writeSize();
@@ -163,7 +163,7 @@
/**
* Writes this instance as an annotation.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
*/
public void writeAnnotation(AnnotatedOutput out) {
out.annotate(toHuman());
diff --git a/dx/src/com/android/dx/dex/file/StringDataItem.java b/dx/src/com/android/dx/dex/file/StringDataItem.java
index 49eea57..b9eeb9b 100644
--- a/dx/src/com/android/dx/dex/file/StringDataItem.java
+++ b/dx/src/com/android/dx/dex/file/StringDataItem.java
@@ -26,13 +26,13 @@
* Representation of string data for a particular string, in a Dalvik file.
*/
public final class StringDataItem extends OffsettedItem {
- /** non-null; the string value */
+ /** {@code non-null;} the string value */
private final CstUtf8 value;
/**
* Constructs an instance.
*
- * @param value non-null; the string value
+ * @param value {@code non-null;} the string value
*/
public StringDataItem(CstUtf8 value) {
super(1, writeSize(value));
@@ -43,8 +43,8 @@
/**
* Gets the write size for a given value.
*
- * @param value non-null; the string value
- * @return >= 2 the write size, in bytes
+ * @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();
diff --git a/dx/src/com/android/dx/dex/file/StringIdItem.java b/dx/src/com/android/dx/dex/file/StringIdItem.java
index e80a7f8..401a0be 100644
--- a/dx/src/com/android/dx/dex/file/StringIdItem.java
+++ b/dx/src/com/android/dx/dex/file/StringIdItem.java
@@ -28,16 +28,16 @@
/** size of instances when written out to a file, in bytes */
public static final int WRITE_SIZE = 4;
- /** non-null; the string value */
+ /** {@code non-null;} the string value */
private final CstUtf8 value;
- /** null-ok; associated string data object, if known */
+ /** {@code null-ok;} associated string data object, if known */
private StringDataItem data;
/**
* Constructs an instance.
*
- * @param value non-null; the string value
+ * @param value {@code non-null;} the string value
*/
public StringIdItem(CstUtf8 value) {
if (value == null) {
@@ -110,7 +110,7 @@
/**
* Gets the string value.
*
- * @return non-null; the value
+ * @return {@code non-null;} the value
*/
public CstUtf8 getValue() {
return value;
@@ -119,7 +119,7 @@
/**
* Gets the associated data object for this instance, if known.
*
- * @return null-ok; the associated data object or <code>null</code>
+ * @return {@code null-ok;} the associated data object or {@code null}
* if not yet known
*/
public StringDataItem getData() {
diff --git a/dx/src/com/android/dx/dex/file/StringIdsSection.java b/dx/src/com/android/dx/dex/file/StringIdsSection.java
index 17fbb57..b2e8683 100644
--- a/dx/src/com/android/dx/dex/file/StringIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/StringIdsSection.java
@@ -27,12 +27,12 @@
import java.util.TreeMap;
/**
- * Strings list section of a <code>.dex</code> file.
+ * Strings list section of a {@code .dex} file.
*/
public final class StringIdsSection
extends UniformItemSection {
/**
- * non-null; map from string constants to {@link
+ * {@code non-null;} map from string constants to {@link
* StringIdItem} instances
*/
private final TreeMap<CstUtf8, StringIdItem> strings;
@@ -40,7 +40,7 @@
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public StringIdsSection(DexFile file) {
super("string_ids", file, 4);
@@ -79,7 +79,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -99,9 +99,9 @@
/**
* Interns an element into this instance.
*
- * @param string non-null; the string to intern, as a regular Java
- * <code>String</code>
- * @return non-null; the interned string
+ * @param string {@code non-null;} the string to intern, as a regular Java
+ * {@code String}
+ * @return {@code non-null;} the interned string
*/
public StringIdItem intern(String string) {
CstUtf8 utf8 = new CstUtf8(string);
@@ -111,8 +111,8 @@
/**
* Interns an element into this instance.
*
- * @param string non-null; the string to intern, as a {@link CstString}
- * @return non-null; the interned string
+ * @param string {@code non-null;} the string to intern, as a {@link CstString}
+ * @return {@code non-null;} the interned string
*/
public StringIdItem intern(CstString string) {
CstUtf8 utf8 = string.getString();
@@ -122,8 +122,8 @@
/**
* Interns an element into this instance.
*
- * @param string non-null; the string to intern, as a constant
- * @return non-null; the interned string
+ * @param string {@code non-null;} the string to intern, as a constant
+ * @return {@code non-null;} the interned string
*/
public StringIdItem intern(CstUtf8 string) {
return intern(new StringIdItem(string));
@@ -132,8 +132,8 @@
/**
* Interns an element into this instance.
*
- * @param string non-null; the string to intern
- * @return non-null; the interned string
+ * @param string {@code non-null;} the string to intern
+ * @return {@code non-null;} the interned string
*/
public StringIdItem intern(StringIdItem string) {
if (string == null) {
@@ -156,7 +156,7 @@
/**
* Interns the components of a name-and-type into this instance.
*
- * @param nat non-null; the name-and-type
+ * @param nat {@code non-null;} the name-and-type
*/
public void intern(CstNat nat) {
intern(nat.getName());
@@ -167,8 +167,8 @@
* Gets the index of the given string, which must have been added
* to this instance.
*
- * @param string non-null; the string to look up
- * @return >= 0; the string's index
+ * @param string {@code non-null;} the string to look up
+ * @return {@code >= 0;} the string's index
*/
public int indexOf(CstUtf8 string) {
if (string == null) {
@@ -190,8 +190,8 @@
* Gets the index of the given string, which must have been added
* to this instance.
*
- * @param string non-null; the string to look up
- * @return >= 0; the string's index
+ * @param string {@code non-null;} the string to look up
+ * @return {@code >= 0;} the string's index
*/
public int indexOf(CstString string) {
return indexOf(string.getString());
diff --git a/dx/src/com/android/dx/dex/file/TypeIdItem.java b/dx/src/com/android/dx/dex/file/TypeIdItem.java
index f3402e6..01b1417 100644
--- a/dx/src/com/android/dx/dex/file/TypeIdItem.java
+++ b/dx/src/com/android/dx/dex/file/TypeIdItem.java
@@ -31,7 +31,7 @@
/**
* Constructs an instance.
*
- * @param type non-null; the constant for the type
+ * @param type {@code non-null;} the constant for the type
*/
public TypeIdItem(CstType type) {
super(type);
diff --git a/dx/src/com/android/dx/dex/file/TypeIdsSection.java b/dx/src/com/android/dx/dex/file/TypeIdsSection.java
index 296263f..b1b9c58 100644
--- a/dx/src/com/android/dx/dex/file/TypeIdsSection.java
+++ b/dx/src/com/android/dx/dex/file/TypeIdsSection.java
@@ -26,18 +26,18 @@
import java.util.TreeMap;
/**
- * Type identifiers list section of a <code>.dex</code> file.
+ * Type identifiers list section of a {@code .dex} file.
*/
public final class TypeIdsSection extends UniformItemSection {
/**
- * non-null; map from types to {@link TypeIdItem} instances
+ * {@code non-null;} map from types to {@link TypeIdItem} instances
*/
private final TreeMap<Type, TypeIdItem> typeIds;
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param file non-null; file that this instance is part of
+ * @param file {@code non-null;} file that this instance is part of
*/
public TypeIdsSection(DexFile file) {
super("type_ids", file, 4);
@@ -73,7 +73,7 @@
/**
* Writes the portion of the file header that refers to this instance.
*
- * @param out non-null; where to write
+ * @param out {@code non-null;} where to write
*/
public void writeHeaderPart(AnnotatedOutput out) {
throwIfNotPrepared();
@@ -97,8 +97,8 @@
/**
* Interns an element into this instance.
*
- * @param type non-null; the type to intern
- * @return non-null; the interned reference
+ * @param type {@code non-null;} the type to intern
+ * @return {@code non-null;} the interned reference
*/
public TypeIdItem intern(Type type) {
if (type == null) {
@@ -120,8 +120,8 @@
/**
* Interns an element into this instance.
*
- * @param type non-null; the type to intern
- * @return non-null; the interned reference
+ * @param type {@code non-null;} the type to intern
+ * @return {@code non-null;} the interned reference
*/
public TypeIdItem intern(CstType type) {
if (type == null) {
@@ -145,8 +145,8 @@
* Gets the index of the given type, which must have
* been added to this instance.
*
- * @param type non-null; the type to look up
- * @return >= 0; the reference's index
+ * @param type {@code non-null;} the type to look up
+ * @return {@code >= 0;} the reference's index
*/
public int indexOf(Type type) {
if (type == null) {
@@ -168,8 +168,8 @@
* Gets the index of the given type, which must have
* been added to this instance.
*
- * @param type non-null; the type to look up
- * @return >= 0; the reference's index
+ * @param type {@code non-null;} the type to look up
+ * @return {@code >= 0;} the reference's index
*/
public int indexOf(CstType type) {
if (type == null) {
diff --git a/dx/src/com/android/dx/dex/file/TypeListItem.java b/dx/src/com/android/dx/dex/file/TypeListItem.java
index 6557ca4..3278aef 100644
--- a/dx/src/com/android/dx/dex/file/TypeListItem.java
+++ b/dx/src/com/android/dx/dex/file/TypeListItem.java
@@ -36,13 +36,13 @@
/** header size in bytes */
private static final int HEADER_SIZE = 4;
- /** non-null; the actual list */
+ /** {@code non-null;} the actual list */
private final TypeList list;
/**
* Constructs an instance.
*
- * @param list non-null; the actual list
+ * @param list {@code non-null;} the actual list
*/
public TypeListItem(TypeList list) {
super(ALIGNMENT, (list.size() * ELEMENT_SIZE) + HEADER_SIZE);
@@ -81,7 +81,7 @@
/**
* Gets the underlying list.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public TypeList getList() {
return list;
diff --git a/dx/src/com/android/dx/dex/file/UniformItemSection.java b/dx/src/com/android/dx/dex/file/UniformItemSection.java
index 602bc2d..e182438 100644
--- a/dx/src/com/android/dx/dex/file/UniformItemSection.java
+++ b/dx/src/com/android/dx/dex/file/UniformItemSection.java
@@ -22,7 +22,7 @@
import java.util.Collection;
/**
- * A section of a <code>.dex</code> file which consists of a sequence of
+ * A section of a {@code .dex} file which consists of a sequence of
* {@link Item} objects. Each of the items must have the same size in
* the output.
*/
@@ -30,10 +30,10 @@
/**
* Constructs an instance. The file offset is initially unknown.
*
- * @param name null-ok; the name of this instance, for annotation
+ * @param name {@code null-ok;} the name of this instance, for annotation
* purposes
- * @param file non-null; file that this instance is part of
- * @param alignment > 0; alignment requirement for the final output;
+ * @param file {@code non-null;} file that this instance is part of
+ * @param alignment {@code > 0;} alignment requirement for the final output;
* must be a power of 2
*/
public UniformItemSection(String name, DexFile file, int alignment) {
@@ -60,8 +60,8 @@
* if this instance isn't the sort that maps constants to {@link
* IndexedItem} instances.
*
- * @param cst non-null; constant to look for
- * @return non-null; the corresponding item found in this instance
+ * @param cst {@code non-null;} constant to look for
+ * @return {@code non-null;} the corresponding item found in this instance
*/
public abstract IndexedItem get(Constant cst);
diff --git a/dx/src/com/android/dx/dex/file/UniformListItem.java b/dx/src/com/android/dx/dex/file/UniformListItem.java
index 3af3942..3c1f4d3 100644
--- a/dx/src/com/android/dx/dex/file/UniformListItem.java
+++ b/dx/src/com/android/dx/dex/file/UniformListItem.java
@@ -28,8 +28,8 @@
* alignment.
*
* <p>This class inherits its alignment from its items, bumped up to
- * <code>4</code> if the items have a looser alignment requirement. If
- * it is more than <code>4</code>, then there will be a gap after the
+ * {@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
@@ -39,18 +39,18 @@
/** the size of the list header */
private static final int HEADER_SIZE = 4;
- /** non-null; the item type */
+ /** {@code non-null;} the item type */
private final ItemType itemType;
- /** non-null; the contents */
+ /** {@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 non-null; the type of the item
- * @param items non-null and non-empty; list of items to represent
+ * @param itemType {@code non-null;} the type of the item
+ * @param items {@code non-null and non-empty;} list of items to represent
*/
public UniformListItem(ItemType itemType, List<T> items) {
super(getAlignment(items), writeSize(items));
@@ -68,8 +68,8 @@
* requirement implied by the given list. See the header comment for
* more details.
*
- * @param items non-null; list of items being represented
- * @return >= 4; the alignment requirement
+ * @param items {@code non-null;} list of items being represented
+ * @return {@code >= 4;} the alignment requirement
*/
private static int getAlignment(List<? extends OffsettedItem> items) {
try {
@@ -87,8 +87,8 @@
/**
* Calculates the write size for the given list.
*
- * @param items non-null; the list in question
- * @return >= 0; the write size
+ * @param items {@code non-null;} the list in question
+ * @return {@code >= 0;} the write size
*/
private static int writeSize(List<? extends OffsettedItem> items) {
/*
@@ -148,7 +148,7 @@
/**
* Gets the underlying list of items.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public final List<T> getItems() {
return items;
@@ -204,7 +204,7 @@
/**
* Get the size of the header of this list.
*
- * @return >= 0; the header size
+ * @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 02a3419..f7e364a 100644
--- a/dx/src/com/android/dx/dex/file/ValueEncoder.java
+++ b/dx/src/com/android/dx/dex/file/ValueEncoder.java
@@ -43,69 +43,69 @@
import java.util.Collection;
/**
- * Handler for writing out <code>encoded_values</code> and parts
+ * Handler for writing out {@code encoded_values} and parts
* thereof.
*/
public final class ValueEncoder {
- /** annotation value type constant: <code>byte</code> */
+ /** annotation value type constant: {@code byte} */
private static final int VALUE_BYTE = 0x00;
- /** annotation value type constant: <code>short</code> */
+ /** annotation value type constant: {@code short} */
private static final int VALUE_SHORT = 0x02;
- /** annotation value type constant: <code>char</code> */
+ /** annotation value type constant: {@code char} */
private static final int VALUE_CHAR = 0x03;
- /** annotation value type constant: <code>int</code> */
+ /** annotation value type constant: {@code int} */
private static final int VALUE_INT = 0x04;
- /** annotation value type constant: <code>long</code> */
+ /** annotation value type constant: {@code long} */
private static final int VALUE_LONG = 0x06;
- /** annotation value type constant: <code>float</code> */
+ /** annotation value type constant: {@code float} */
private static final int VALUE_FLOAT = 0x10;
- /** annotation value type constant: <code>double</code> */
+ /** annotation value type constant: {@code double} */
private static final int VALUE_DOUBLE = 0x11;
- /** annotation value type constant: <code>string</code> */
+ /** annotation value type constant: {@code string} */
private static final int VALUE_STRING = 0x17;
- /** annotation value type constant: <code>type</code> */
+ /** annotation value type constant: {@code type} */
private static final int VALUE_TYPE = 0x18;
- /** annotation value type constant: <code>field</code> */
+ /** annotation value type constant: {@code field} */
private static final int VALUE_FIELD = 0x19;
- /** annotation value type constant: <code>method</code> */
+ /** annotation value type constant: {@code method} */
private static final int VALUE_METHOD = 0x1a;
- /** annotation value type constant: <code>enum</code> */
+ /** annotation value type constant: {@code enum} */
private static final int VALUE_ENUM = 0x1b;
- /** annotation value type constant: <code>array</code> */
+ /** annotation value type constant: {@code array} */
private static final int VALUE_ARRAY = 0x1c;
- /** annotation value type constant: <code>annotation</code> */
+ /** annotation value type constant: {@code annotation} */
private static final int VALUE_ANNOTATION = 0x1d;
- /** annotation value type constant: <code>null</code> */
+ /** annotation value type constant: {@code null} */
private static final int VALUE_NULL = 0x1e;
- /** annotation value type constant: <code>boolean</code> */
+ /** annotation value type constant: {@code boolean} */
private static final int VALUE_BOOLEAN = 0x1f;
- /** non-null; file being written */
+ /** {@code non-null;} file being written */
private final DexFile file;
- /** non-null; output stream to write to */
+ /** {@code non-null;} output stream to write to */
private final AnnotatedOutput out;
/**
* Construct an instance.
*
- * @param file non-null; file being written
- * @param out non-null; output stream to write to
+ * @param file {@code non-null;} file being written
+ * @param out {@code non-null;} output stream to write to
*/
public ValueEncoder(DexFile file, AnnotatedOutput out) {
if (file == null) {
@@ -123,7 +123,7 @@
/**
* Writes out the encoded form of the given constant.
*
- * @param cst non-null; the constant to write
+ * @param cst {@code non-null;} the constant to write
*/
public void writeConstant(Constant cst) {
int type = constantToValueType(cst);
@@ -209,8 +209,8 @@
/**
* Gets the value type for the given constant.
*
- * @param cst non-null; the constant
- * @return the value type; one of the <code>VALUE_*</code> constants
+ * @param cst {@code non-null;} the constant
+ * @return the value type; one of the {@code VALUE_*} constants
* defined by this class
*/
private static int constantToValueType(Constant cst) {
@@ -257,15 +257,15 @@
/**
* Writes out the encoded form of the given array, that is, as
- * an <code>encoded_array</code> and not including a
- * <code>value_type</code> prefix. If the output stream keeps
- * (debugging) annotations and <code>topLevel</code> is
- * <code>true</code>, then this method will write (debugging)
+ * an {@code encoded_array} and not including a
+ * {@code value_type} prefix. If the output stream keeps
+ * (debugging) annotations and {@code topLevel} is
+ * {@code true}, then this method will write (debugging)
* annotations.
*
- * @param array non-null; array instance to write
- * @param topLevel <code>true</code> iff the given annotation is the
- * top-level annotation or <code>false</code> if it is a sub-annotation
+ * @param array {@code non-null;} array 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
* of some other annotation
*/
public void writeArray(CstArray array, boolean topLevel) {
@@ -295,15 +295,15 @@
/**
* Writes out the encoded form of the given annotation, that is,
- * as an <code>encoded_annotation</code> and not including a
- * <code>value_type</code> prefix. If the output stream keeps
- * (debugging) annotations and <code>topLevel</code> is
- * <code>true</code>, then this method will write (debugging)
+ * as an {@code encoded_annotation} and not including a
+ * {@code value_type} prefix. If the output stream keeps
+ * (debugging) annotations and {@code topLevel} is
+ * {@code true}, then this method will write (debugging)
* annotations.
*
- * @param annotation non-null; annotation instance to write
- * @param topLevel <code>true</code> iff the given annotation is the
- * top-level annotation or <code>false</code> if it is a sub-annotation
+ * @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
* of some other annotation
*/
public void writeAnnotation(Annotation annotation, boolean topLevel) {
@@ -361,8 +361,8 @@
* Gets the colloquial type name and human form of the type of the
* given constant, when used as an encoded value.
*
- * @param cst non-null; the constant
- * @return non-null; its type name and human form
+ * @param cst {@code non-null;} the constant
+ * @return {@code non-null;} its type name and human form
*/
public static String constantToHuman(Constant cst) {
int type = constantToValueType(cst);
@@ -385,7 +385,7 @@
* for any signed integral type.
*
* @param type the type constant
- * @param value <code>long</code> bits of the value
+ * @param value {@code long} bits of the value
*/
private void writeSignedIntegralValue(int type, long value) {
/*
@@ -422,7 +422,7 @@
* for any unsigned integral type.
*
* @param type the type constant
- * @param value <code>long</code> bits of the value
+ * @param value {@code long} bits of the value
*/
private void writeUnsignedIntegralValue(int type, long value) {
// Figure out how many bits are needed to represent the value.
@@ -453,7 +453,7 @@
* right-zero-extended value.
*
* @param type the type constant
- * @param value <code>long</code> bits of the value
+ * @param value {@code long} bits of the value
*/
private void writeRightZeroExtendedValue(int type, long value) {
// Figure out how many bits are needed to represent the value.
@@ -484,12 +484,12 @@
/**
- * Helper for <code>addContents()</code> methods, which adds
+ * Helper for {@code addContents()} methods, which adds
* contents for a particular {@link Annotation}, calling itself
* recursively should it encounter a nested annotation.
*
- * @param file non-null; the file to add to
- * @param annotation non-null; the annotation to add contents for
+ * @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) {
TypeIdsSection typeIds = file.getTypeIds();
@@ -504,19 +504,16 @@
}
/**
- * Helper for <code>addContents()</code> methods, which adds
+ * Helper for {@code addContents()} methods, which adds
* contents for a particular constant, calling itself recursively
* should it encounter a {@link CstArray} and calling {@link
* #addContents(DexFile,Annotation)} recursively should it
* encounter a {@link CstAnnotation}.
*
- * @param file non-null; the file to add to
- * @param cst non-null; the constant to add contents for
+ * @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) {
- TypeIdsSection typeIds = file.getTypeIds();
- StringIdsSection stringIds = file.getStringIds();
-
if (cst instanceof CstAnnotation) {
addContents(file, ((CstAnnotation) cst).getAnnotation());
} else if (cst instanceof CstArray) {
diff --git a/dx/src/com/android/dx/rop/annotation/Annotation.java b/dx/src/com/android/dx/rop/annotation/Annotation.java
index b7cf164..6154c61 100644
--- a/dx/src/com/android/dx/rop/annotation/Annotation.java
+++ b/dx/src/com/android/dx/rop/annotation/Annotation.java
@@ -41,20 +41,20 @@
*/
public final class Annotation extends MutabilityControl
implements Comparable<Annotation>, ToHuman {
- /** non-null; type of the annotation */
+ /** {@code non-null;} type of the annotation */
private final CstType type;
- /** non-null; the visibility of the annotation */
+ /** {@code non-null;} the visibility of the annotation */
private final AnnotationVisibility visibility;
- /** non-null; map from names to {@link NameValuePair} instances */
+ /** {@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 non-null; type of the annotation
- * @param visibility non-null; the visibility of the annotation
+ * @param type {@code non-null;} type of the annotation
+ * @param visibility {@code non-null;} the visibility of the annotation
*/
public Annotation(CstType type, AnnotationVisibility visibility) {
if (type == null) {
@@ -165,7 +165,7 @@
/**
* Gets the type of this instance.
*
- * @return non-null; the type
+ * @return {@code non-null;} the type
*/
public CstType getType() {
return type;
@@ -174,7 +174,7 @@
/**
* Gets the visibility of this instance.
*
- * @return non-null; the visibility
+ * @return {@code non-null;} the visibility
*/
public AnnotationVisibility getVisibility() {
return visibility;
@@ -185,7 +185,7 @@
* If there is a preexisting element with the same name, it will be
* replaced by this method.
*
- * @param pair non-null; the (name, value) pair to place into this instance
+ * @param pair {@code non-null;} the (name, value) pair to place into this instance
*/
public void put(NameValuePair pair) {
throwIfImmutable();
@@ -202,7 +202,7 @@
* It is an error to call this method if there is a preexisting element
* with the same name.
*
- * @param pair non-null; the (name, value) pair to add to this instance
+ * @param pair {@code non-null;} the (name, value) pair to add to this instance
*/
public void add(NameValuePair pair) {
throwIfImmutable();
@@ -224,7 +224,7 @@
* Gets the set of name-value pairs contained in this instance. The
* result is always unmodifiable.
*
- * @return non-null; the set of name-value pairs
+ * @return {@code non-null;} the set of name-value pairs
*/
public Collection<NameValuePair> getNameValuePairs() {
return Collections.unmodifiableCollection(elements.values());
diff --git a/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java b/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
index c53fcd8..26246bb 100644
--- a/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
+++ b/dx/src/com/android/dx/rop/annotation/AnnotationVisibility.java
@@ -27,13 +27,13 @@
SYSTEM("system"),
EMBEDDED("embedded");
- /** non-null; the human-oriented string representation */
+ /** {@code non-null;} the human-oriented string representation */
private final String human;
/**
* Constructs an instance.
*
- * @param human non-null; the human-oriented string representation
+ * @param human {@code non-null;} the human-oriented string representation
*/
private AnnotationVisibility(String human) {
this.human = human;
diff --git a/dx/src/com/android/dx/rop/annotation/Annotations.java b/dx/src/com/android/dx/rop/annotation/Annotations.java
index c1da883..dcb74a1 100644
--- a/dx/src/com/android/dx/rop/annotation/Annotations.java
+++ b/dx/src/com/android/dx/rop/annotation/Annotations.java
@@ -29,14 +29,14 @@
*/
public final class Annotations extends MutabilityControl
implements Comparable<Annotations> {
- /** non-null; immutable empty instance */
+ /** {@code non-null;} immutable empty instance */
public static final Annotations EMPTY = new Annotations();
static {
EMPTY.setImmutable();
}
- /** non-null; map from types to annotations */
+ /** {@code non-null;} map from types to annotations */
private final TreeMap<CstType, Annotation> annotations;
/**
@@ -44,9 +44,9 @@
* two given instances. The two instances must contain disjoint sets
* of types.
*
- * @param a1 non-null; an instance
- * @param a2 non-null; the other instance
- * @return non-null; the combination
+ * @param a1 {@code non-null;} an instance
+ * @param a2 {@code non-null;} the other instance
+ * @return {@code non-null;} the combination
* @throws IllegalArgumentException thrown if there is a duplicate type
*/
public static Annotations combine(Annotations a1, Annotations a2) {
@@ -64,9 +64,9 @@
* given instance with the given additional annotation. The latter's
* type must not already appear in the former.
*
- * @param annotations non-null; the instance to augment
- * @param annotation non-null; the additional annotation
- * @return non-null; the combination
+ * @param annotations {@code non-null;} the instance to augment
+ * @param annotation {@code non-null;} the additional annotation
+ * @return {@code non-null;} the combination
* @throws IllegalArgumentException thrown if there is a duplicate type
*/
public static Annotations combine(Annotations annotations,
@@ -152,7 +152,7 @@
/**
* Gets the number of elements in this instance.
*
- * @return >= 0; the size
+ * @return {@code >= 0;} the size
*/
public int size() {
return annotations.size();
@@ -162,7 +162,7 @@
* Adds an element to this instance. There must not already be an
* element of the same type.
*
- * @param annotation non-null; the element to add
+ * @param annotation {@code non-null;} the element to add
* @throws IllegalArgumentException thrown if there is a duplicate type
*/
public void add(Annotation annotation) {
@@ -186,7 +186,7 @@
* Adds all of the elements of the given instance to this one. The
* instances must not have any duplicate types.
*
- * @param toAdd non-null; the annotations to add
+ * @param toAdd {@code non-null;} the annotations to add
* @throws IllegalArgumentException thrown if there is a duplicate type
*/
public void addAll(Annotations toAdd) {
@@ -205,7 +205,7 @@
* Gets the set of annotations contained in this instance. The
* result is always unmodifiable.
*
- * @return non-null; the set of annotations
+ * @return {@code non-null;} the set of annotations
*/
public Collection<Annotation> getAnnotations() {
return Collections.unmodifiableCollection(annotations.values());
diff --git a/dx/src/com/android/dx/rop/annotation/AnnotationsList.java b/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
index 43a07ba..0f4207b 100644
--- a/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
+++ b/dx/src/com/android/dx/rop/annotation/AnnotationsList.java
@@ -23,7 +23,7 @@
*/
public final class AnnotationsList
extends FixedSizeList {
- /** non-null; immutable empty instance */
+ /** {@code non-null;} immutable empty instance */
public static final AnnotationsList EMPTY = new AnnotationsList(0);
/**
@@ -32,9 +32,9 @@
* same number of elements, and each pair of elements must contain
* disjoint sets of types.
*
- * @param list1 non-null; an instance
- * @param list2 non-null; the other instance
- * @return non-null; the combination
+ * @param list1 {@code non-null;} an instance
+ * @param list2 {@code non-null;} the other instance
+ * @return {@code non-null;} the combination
*/
public static AnnotationsList combine(AnnotationsList list1,
AnnotationsList list2) {
@@ -57,7 +57,7 @@
}
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -68,10 +68,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Annotations get(int n) {
return (Annotations) get0(n);
@@ -81,8 +81,8 @@
* Sets the element at the given index. The given element must be
* immutable.
*
- * @param n >= 0, < size(); which index
- * @param a null-ok; the element to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param a {@code null-ok;} the element to set at {@code n}
*/
public void set(int n, Annotations a) {
a.throwIfMutable();
diff --git a/dx/src/com/android/dx/rop/annotation/NameValuePair.java b/dx/src/com/android/dx/rop/annotation/NameValuePair.java
index dadabaa..7137a60 100644
--- a/dx/src/com/android/dx/rop/annotation/NameValuePair.java
+++ b/dx/src/com/android/dx/rop/annotation/NameValuePair.java
@@ -24,17 +24,17 @@
* A (name, value) pair. These are used as the contents of an annotation.
*/
public final class NameValuePair implements Comparable<NameValuePair> {
- /** non-null; the name */
+ /** {@code non-null;} the name */
private final CstUtf8 name;
- /** non-null; the value */
+ /** {@code non-null;} the value */
private final Constant value;
/**
* Construct an instance.
*
- * @param name non-null; the name
- * @param value non-null; the value
+ * @param name {@code non-null;} the name
+ * @param value {@code non-null;} the value
*/
public NameValuePair(CstUtf8 name, Constant value) {
if (name == null) {
@@ -95,7 +95,7 @@
/**
* Gets the name.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public CstUtf8 getName() {
return name;
@@ -104,7 +104,7 @@
/**
* Gets the value.
*
- * @return non-null; the valute
+ * @return {@code non-null;} the value
*/
public Constant getValue() {
return value;
diff --git a/dx/src/com/android/dx/rop/code/AccessFlags.java b/dx/src/com/android/dx/rop/code/AccessFlags.java
index 265cfa6..b76b610 100644
--- a/dx/src/com/android/dx/rop/code/AccessFlags.java
+++ b/dx/src/com/android/dx/rop/code/AccessFlags.java
@@ -23,8 +23,8 @@
* related utilities. Although, at the rop layer, flags are generally
* ignored, this is the layer of communication, and as such, this
* package is where these definitions belong. The flag definitions are
- * identical to Java access flags, but <code>ACC_SUPER</code> isn't
- * used at all in translated code, and <code>ACC_SYNCHRONIZED</code>
+ * identical to Java access flags, but {@code ACC_SUPER} isn't
+ * used at all in translated code, and {@code ACC_SYNCHRONIZED}
* is only used in a very limited way.
*/
public final class AccessFlags {
@@ -44,13 +44,13 @@
public static final int ACC_FINAL = 0x0010;
/**
- * synchronized method; only valid in dex files for <code>native</code>
+ * synchronized method; only valid in dex files for {@code native}
* methods
*/
public static final int ACC_SYNCHRONIZED = 0x0020;
/**
- * class with new-style <code>invokespecial</code> for superclass
+ * class with new-style {@code invokespecial} for superclass
* method access
*/
public static final int ACC_SUPER = 0x0020;
@@ -77,7 +77,7 @@
public static final int ACC_ABSTRACT = 0x0400;
/**
- * method with strict floating point (<code>strictfp</code>)
+ * method with strict floating point ({@code strictfp})
* behavior
*/
public static final int ACC_STRICT = 0x0800;
@@ -98,7 +98,7 @@
public static final int ACC_CONSTRUCTOR = 0x10000;
/**
- * method was declared <code>synchronized</code>; has no effect on
+ * method was declared {@code synchronized}; has no effect on
* execution (other than inspecting this flag, per se)
*/
public static final int ACC_DECLARED_SYNCHRONIZED = 0x20000;
@@ -147,7 +147,7 @@
* as defined on classes (not fields or methods).
*
* @param flags the flags
- * @return non-null; human-oriented string
+ * @return {@code non-null;} human-oriented string
*/
public static String classString(int flags) {
return humanHelper(flags, CLASS_FLAGS, CONV_CLASS);
@@ -158,7 +158,7 @@
* as defined on inner classes.
*
* @param flags the flags
- * @return non-null; human-oriented string
+ * @return {@code non-null;} human-oriented string
*/
public static String innerClassString(int flags) {
return humanHelper(flags, INNER_CLASS_FLAGS, CONV_CLASS);
@@ -169,7 +169,7 @@
* as defined on fields (not classes or methods).
*
* @param flags the flags
- * @return non-null; human-oriented string
+ * @return {@code non-null;} human-oriented string
*/
public static String fieldString(int flags) {
return humanHelper(flags, FIELD_FLAGS, CONV_FIELD);
@@ -180,106 +180,106 @@
* as defined on methods (not classes or fields).
*
* @param flags the flags
- * @return non-null; human-oriented string
+ * @return {@code non-null;} human-oriented string
*/
public static String methodString(int flags) {
return humanHelper(flags, METHOD_FLAGS, CONV_METHOD);
}
/**
- * Returns whether the flag <code>ACC_PUBLIC</code> is on in the given
+ * 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</code> flag
+ * @return the value of the {@code ACC_PUBLIC} flag
*/
public static boolean isPublic(int flags) {
return (flags & ACC_PUBLIC) != 0;
}
/**
- * Returns whether the flag <code>ACC_PROTECTED</code> is on in the given
+ * 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</code> flag
+ * @return the value of the {@code ACC_PROTECTED} flag
*/
public static boolean isProtected(int flags) {
return (flags & ACC_PROTECTED) != 0;
}
/**
- * Returns whether the flag <code>ACC_PRIVATE</code> is on in the given
+ * 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</code> flag
+ * @return the value of the {@code ACC_PRIVATE} flag
*/
public static boolean isPrivate(int flags) {
return (flags & ACC_PRIVATE) != 0;
}
/**
- * Returns whether the flag <code>ACC_STATIC</code> is on in the given
+ * 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</code> flag
+ * @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</code> is on in
+ * 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</code> flag
+ * @return the value of the {@code ACC_SYNCHRONIZED} flag
*/
public static boolean isSynchronized(int flags) {
return (flags & ACC_SYNCHRONIZED) != 0;
}
/**
- * Returns whether the flag <code>ACC_ABSTRACT</code> is on in the given
+ * 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</code> flag
+ * @return the value of the {@code ACC_ABSTRACT} flag
*/
public static boolean isAbstract(int flags) {
return (flags & ACC_ABSTRACT) != 0;
}
/**
- * Returns whether the flag <code>ACC_NATIVE</code> is on in the given
+ * 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</code> flag
+ * @return the value of the {@code ACC_NATIVE} flag
*/
public static boolean isNative(int flags) {
return (flags & ACC_NATIVE) != 0;
}
/**
- * Returns whether the flag <code>ACC_ANNOTATION</code> is on in the given
+ * 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</code> flag
+ * @return the value of the {@code ACC_ANNOTATION} flag
*/
public static boolean isAnnotation(int flags) {
return (flags & ACC_ANNOTATION) != 0;
}
/**
- * Returns whether the flag <code>ACC_DECLARED_SYNCHRONIZED</code> is
+ * 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</code> flag
+ * @return the value of the {@code ACC_DECLARED_SYNCHRONIZED} flag
*/
public static boolean isDeclaredSynchronized(int flags) {
return (flags & ACC_DECLARED_SYNCHRONIZED) != 0;
@@ -291,8 +291,8 @@
*
* @param flags the defined flags
* @param mask mask for the "defined" bits
- * @param what what the flags represent (one of <code>CONV_*</code>)
- * @return non-null; human-oriented string
+ * @param what what the flags represent (one of {@code CONV_*})
+ * @return {@code non-null;} human-oriented string
*/
private static String humanHelper(int flags, int mask, int what) {
StringBuffer sb = new StringBuffer(80);
diff --git a/dx/src/com/android/dx/rop/code/BasicBlock.java b/dx/src/com/android/dx/rop/code/BasicBlock.java
index 66db5aa..7bb2d9b 100644
--- a/dx/src/com/android/dx/rop/code/BasicBlock.java
+++ b/dx/src/com/android/dx/rop/code/BasicBlock.java
@@ -25,34 +25,34 @@
* Basic block of register-based instructions.
*/
public final class BasicBlock implements LabeledItem {
- /** >= 0; target label for this block */
+ /** {@code >= 0;} target label for this block */
private final int label;
- /** non-null; list of instructions in this block */
+ /** {@code non-null;} list of instructions in this block */
private final InsnList insns;
/**
- * non-null; full list of successors that this block may
+ * {@code non-null;} full list of successors that this block may
* branch to
*/
private final IntList successors;
/**
- * >= -1; the primary / standard-flow / "default" successor, or
- * <code>-1</code> if this block has no successors (that is, it
+ * {@code >= -1;} the primary / standard-flow / "default" successor, or
+ * {@code -1} if this block has no successors (that is, it
* exits the function/method)
*/
private final int primarySuccessor;
/**
- * Constructs an instance. The predecessor set is set to <code>null</code>.
+ * Constructs an instance. The predecessor set is set to {@code null}.
*
- * @param label >= 0; target label for this block
- * @param insns non-null; list of instructions in this block
- * @param successors non-null; full list of successors that this
+ * @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
* block may branch to
- * @param primarySuccessor >= -1; the primary / standard-flow /
- * "default" successor, or <code>-1</code> if this block has no
+ * @param primarySuccessor {@code >= -1;} the primary / standard-flow /
+ * "default" successor, or {@code -1} if this block has no
* successors (that is, it exits the function/method or is an
* unconditional throw)
*/
@@ -116,7 +116,7 @@
* {@inheritDoc}
*
* Instances of this class compare by identity. That is,
- * <code>x.equals(y)</code> is only true if <code>x == y</code>.
+ * {@code x.equals(y)} is only true if {@code x == y}.
*/
@Override
public boolean equals(Object other) {
@@ -137,7 +137,7 @@
/**
* Gets the target label of this block.
*
- * @return >= 0; the label
+ * @return {@code >= 0;} the label
*/
public int getLabel() {
return label;
@@ -146,7 +146,7 @@
/**
* Gets the list of instructions inside this block.
*
- * @return non-null; the instruction list
+ * @return {@code non-null;} the instruction list
*/
public InsnList getInsns() {
return insns;
@@ -155,7 +155,7 @@
/**
* Gets the list of successors that this block may branch to.
*
- * @return non-null; the successors list
+ * @return {@code non-null;} the successors list
*/
public IntList getSuccessors() {
return successors;
@@ -164,7 +164,7 @@
/**
* Gets the primary successor of this block.
*
- * @return >= -1; the primary successor, or <code>-1</code> if this
+ * @return {@code >= -1;} the primary successor, or {@code -1} if this
* block has no successors at all
*/
public int getPrimarySuccessor() {
@@ -175,7 +175,7 @@
* Gets the secondary successor of this block. It is only valid to call
* this method on blocks that have exactly two successors.
*
- * @return >= 0; the secondary successor
+ * @return {@code >= 0;} the secondary successor
*/
public int getSecondarySuccessor() {
if (successors.size() != 2) {
@@ -193,9 +193,9 @@
/**
* Gets the first instruction of this block. This is just a
- * convenient shorthand for <code>getInsns().get(0)</code>.
+ * convenient shorthand for {@code getInsns().get(0)}.
*
- * @return non-null; the first instruction
+ * @return {@code non-null;} the first instruction
*/
public Insn getFirstInsn() {
return insns.get(0);
@@ -203,9 +203,9 @@
/**
* Gets the last instruction of this block. This is just a
- * convenient shorthand for <code>getInsns().getLast()</code>.
+ * convenient shorthand for {@code getInsns().getLast()}.
*
- * @return non-null; the last instruction
+ * @return {@code non-null;} the last instruction
*/
public Insn getLastInsn() {
return insns.getLast();
@@ -213,9 +213,9 @@
/**
* Returns whether this block might throw an exception. This is
- * just a convenient shorthand for <code>getLastInsn().canThrow()</code>.
+ * just a convenient shorthand for {@code getLastInsn().canThrow()}.
*
- * @return <code>true</code> iff this block might throw an
+ * @return {@code true} iff this block might throw an
* exception
*/
public boolean canThrow() {
@@ -228,7 +228,7 @@
* the block to see if it could throw, and if so, whether it in fact
* has any associated handlers.
*
- * @return <code>true</code> iff this block has any associated
+ * @return {@code true} iff this block has any associated
* exception handlers
*/
public boolean hasExceptionHandlers() {
@@ -241,9 +241,9 @@
* if any. This is just a shorthand for inspecting the last
* instruction in the block to see if it could throw, and if so,
* grabbing the catch list out of it. If not, this returns an
- * empty list (not <code>null</code>).
+ * empty list (not {@code null}).
*
- * @return non-null; the exception handler types associated with
+ * @return {@code non-null;} the exception handler types associated with
* this block
*/
public TypeList getExceptionHandlerTypes() {
@@ -257,7 +257,7 @@
* amount.
*
* @param delta the amount to offset register numbers by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public BasicBlock withRegisterOffset(int delta) {
return new BasicBlock(label, insns.withRegisterOffset(delta),
diff --git a/dx/src/com/android/dx/rop/code/BasicBlockList.java b/dx/src/com/android/dx/rop/code/BasicBlockList.java
index 6564318..0627425 100644
--- a/dx/src/com/android/dx/rop/code/BasicBlockList.java
+++ b/dx/src/com/android/dx/rop/code/BasicBlockList.java
@@ -27,14 +27,14 @@
*/
public final class BasicBlockList extends LabeledList {
/**
- * >= -1; the count of registers required by this method or
- * <code>-1</code> if not yet calculated
+ * {@code >= -1;} the count of registers required by this method or
+ * {@code -1} if not yet calculated
*/
private int regCount;
/**
- * Constructs an instance. All indices initially contain <code>null</code>,
- * and the first-block label is initially <code>-1</code>.
+ * 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
*/
@@ -45,7 +45,7 @@
}
/**
- * Constructs a mutable copy for <code>getMutableCopy()</code>.
+ * Constructs a mutable copy for {@code getMutableCopy()}.
*
* @param old block to copy
*/
@@ -58,10 +58,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public BasicBlock get(int n) {
return (BasicBlock) get0(n);
@@ -70,8 +70,8 @@
/**
* Sets the basic block at the given index.
*
- * @param n >= 0, < size(); which index
- * @param bb null-ok; the element to set at <code>n</code>
+ * @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);
@@ -86,7 +86,7 @@
* instance's instructions (indirectly through {@link BasicBlock}
* instances).
*
- * @return >= 0; the register count
+ * @return {@code >= 0;} the register count
*/
public int getRegCount() {
if (regCount == -1) {
@@ -102,7 +102,7 @@
* Gets the total instruction count for this instance. This is the
* sum of the instruction counts of each block.
*
- * @return >= 0; the total instruction count
+ * @return {@code >= 0;} the total instruction count
*/
public int getInstructionCount() {
int sz = size();
@@ -122,7 +122,7 @@
* Gets the total instruction count for this instance, ignoring
* mark-local instructions which are not actually emitted.
*
- * @return >= 0; the total instruction count
+ * @return {@code >= 0;} the total instruction count
*/
public int getEffectiveInstructionCount() {
int sz = size();
@@ -151,8 +151,8 @@
/**
* Gets the first block in the list with the given label, if any.
*
- * @param label >= 0; the label to look for
- * @return non-null; the so-labelled block
+ * @param label {@code >= 0;} the label to look for
+ * @return {@code non-null;} the so-labelled block
* @throws IllegalArgumentException thrown if the label isn't found
*/
public BasicBlock labelToBlock(int label) {
@@ -169,7 +169,7 @@
/**
* Visits each instruction of each block in the list, in order.
*
- * @param visitor non-null; visitor to use
+ * @param visitor {@code non-null;} visitor to use
*/
public void forEachInsn(Insn.Visitor visitor) {
int sz = size();
@@ -188,7 +188,7 @@
* original.
*
* @param delta the amount to offset register numbers by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public BasicBlockList withRegisterOffset(int delta) {
int sz = size();
@@ -211,7 +211,7 @@
/**
* Returns a mutable copy of this list.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public BasicBlockList getMutableCopy() {
return new BasicBlockList(this);
@@ -222,10 +222,10 @@
* only has one successor, then that is the preferred successor.
* 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</code>.
+ * this returns {@code null}.
*
- * @param block non-null; the block in question
- * @return null-ok; the preferred successor, if any
+ * @param block {@code non-null;} the block in question
+ * @return {@code null-ok;} the preferred successor, if any
*/
public BasicBlock preferredSuccessorOf(BasicBlock block) {
int primarySuccessor = block.getPrimarySuccessor();
@@ -252,9 +252,9 @@
* Compares the catches of two blocks for equality. This includes
* both the catch types and target labels.
*
- * @param block1 non-null; one block to compare
- * @param block2 non-null; the other block to compare
- * @return <code>true</code> if the two blocks' non-primary successors
+ * @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
* are identical
*/
public boolean catchesEqual(BasicBlock block1,
@@ -313,7 +313,7 @@
*/
private static class RegCountVisitor
implements Insn.Visitor {
- /** >= 0; register count in-progress */
+ /** {@code >= 0;} register count in-progress */
private int regCount;
/**
@@ -326,7 +326,7 @@
/**
* Gets the register count.
*
- * @return >= 0; the count
+ * @return {@code >= 0;} the count
*/
public int getRegCount() {
return regCount;
@@ -363,9 +363,9 @@
}
/**
- * Helper for all the <code>visit*</code> methods.
+ * Helper for all the {@code visit*} methods.
*
- * @param insn non-null; instruction being visited
+ * @param insn {@code non-null;} instruction being visited
*/
private void visit(Insn insn) {
RegisterSpec result = insn.getResult();
@@ -385,7 +385,7 @@
/**
* Processes the given register spec.
*
- * @param spec non-null; the register spec
+ * @param spec {@code non-null;} the register spec
*/
private void processReg(RegisterSpec spec) {
int reg = spec.getNextReg();
diff --git a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
index a9da109..1ecf02c 100644
--- a/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
+++ b/dx/src/com/android/dx/rop/code/ConservativeTranslationAdvice.java
@@ -18,11 +18,11 @@
/**
* Implementation of {@link TranslationAdvice} which conservatively answers
- * <code>false</code> to all methods.
+ * {@code false} to all methods.
*/
public final class ConservativeTranslationAdvice
implements TranslationAdvice {
- /** non-null; standard instance of this class */
+ /** {@code non-null;} standard instance of this class */
public static final ConservativeTranslationAdvice THE_ONE =
new ConservativeTranslationAdvice();
diff --git a/dx/src/com/android/dx/rop/code/CstInsn.java b/dx/src/com/android/dx/rop/code/CstInsn.java
index d1cf523..26df1a9 100644
--- a/dx/src/com/android/dx/rop/code/CstInsn.java
+++ b/dx/src/com/android/dx/rop/code/CstInsn.java
@@ -23,17 +23,17 @@
*/
public abstract class CstInsn
extends Insn {
- /** non-null; the constant */
+ /** {@code non-null;} the constant */
private final Constant cst;
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param result null-ok; spec for the result, if any
- * @param sources non-null; specs for all the sources
- * @param cst non-null; constant
+ * @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
+ * @param sources {@code non-null;} specs for all the sources
+ * @param cst {@code non-null;} constant
*/
public CstInsn(Rop opcode, SourcePosition position, RegisterSpec result,
RegisterSpecList sources, Constant cst) {
@@ -55,7 +55,7 @@
/**
* Gets the constant.
*
- * @return non-null; the constant
+ * @return {@code non-null;} the constant
*/
public Constant getConstant() {
return cst;
diff --git a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
index 1c23824..8dbc00b 100644
--- a/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
+++ b/dx/src/com/android/dx/rop/code/DexTranslationAdvice.java
@@ -25,7 +25,7 @@
*/
public final class DexTranslationAdvice
implements TranslationAdvice {
- /** non-null; standard instance of this class */
+ /** {@code non-null;} standard instance of this class */
public static final DexTranslationAdvice THE_ONE =
new DexTranslationAdvice();
@@ -98,8 +98,8 @@
/**
* Calculates the total rop width of the list of SSA registers
*
- * @param sources non-null; list of SSA registers
- * @return >= 0 rop-form width in register units
+ * @param sources {@code non-null;} list of SSA registers
+ * @return {@code >= 0;} rop-form width in register units
*/
private int totalRopWidth(RegisterSpecList sources) {
int sz = sources.size();
diff --git a/dx/src/com/android/dx/rop/code/Exceptions.java b/dx/src/com/android/dx/rop/code/Exceptions.java
index 3ef4879..f99a760 100644
--- a/dx/src/com/android/dx/rop/code/Exceptions.java
+++ b/dx/src/com/android/dx/rop/code/Exceptions.java
@@ -23,78 +23,78 @@
* Common exception types.
*/
public final class Exceptions {
- /** non-null; the type <code>java.lang.ArithmeticException</code> */
+ /** {@code non-null;} the type {@code java.lang.ArithmeticException} */
public static final Type TYPE_ArithmeticException =
Type.intern("Ljava/lang/ArithmeticException;");
/**
- * non-null; the type
- * <code>java.lang.ArrayIndexOutOfBoundsException</code>
+ * {@code non-null;} the type
+ * {@code java.lang.ArrayIndexOutOfBoundsException}
*/
public static final Type TYPE_ArrayIndexOutOfBoundsException =
Type.intern("Ljava/lang/ArrayIndexOutOfBoundsException;");
- /** non-null; the type <code>java.lang.ArrayStoreException</code> */
+ /** {@code non-null;} the type {@code java.lang.ArrayStoreException} */
public static final Type TYPE_ArrayStoreException =
Type.intern("Ljava/lang/ArrayStoreException;");
- /** non-null; the type <code>java.lang.ClassCastException</code> */
+ /** {@code non-null;} the type {@code java.lang.ClassCastException} */
public static final Type TYPE_ClassCastException =
Type.intern("Ljava/lang/ClassCastException;");
- /** non-null; the type <code>java.lang.Error</code> */
+ /** {@code non-null;} the type {@code java.lang.Error} */
public static final Type TYPE_Error = Type.intern("Ljava/lang/Error;");
/**
- * non-null; the type
- * <code>java.lang.IllegalMonitorStateException</code>
+ * {@code non-null;} the type
+ * {@code java.lang.IllegalMonitorStateException}
*/
public static final Type TYPE_IllegalMonitorStateException =
Type.intern("Ljava/lang/IllegalMonitorStateException;");
- /** non-null; the type <code>java.lang.NegativeArraySizeException</code> */
+ /** {@code non-null;} the type {@code java.lang.NegativeArraySizeException} */
public static final Type TYPE_NegativeArraySizeException =
Type.intern("Ljava/lang/NegativeArraySizeException;");
- /** non-null; the type <code>java.lang.NullPointerException</code> */
+ /** {@code non-null;} the type {@code java.lang.NullPointerException} */
public static final Type TYPE_NullPointerException =
Type.intern("Ljava/lang/NullPointerException;");
- /** non-null; the list <code>[java.lang.Error]</code> */
+ /** {@code non-null;} the list {@code [java.lang.Error]} */
public static final StdTypeList LIST_Error = StdTypeList.make(TYPE_Error);
/**
- * non-null; the list <code>[java.lang.Error,
- * java.lang.ArithmeticException]</code>
+ * {@code non-null;} the list {@code[java.lang.Error,
+ * java.lang.ArithmeticException]}
*/
public static final StdTypeList LIST_Error_ArithmeticException =
StdTypeList.make(TYPE_Error, TYPE_ArithmeticException);
/**
- * non-null; the list <code>[java.lang.Error,
- * java.lang.ClassCastException]</code>
+ * {@code non-null;} the list {@code[java.lang.Error,
+ * java.lang.ClassCastException]}
*/
public static final StdTypeList LIST_Error_ClassCastException =
StdTypeList.make(TYPE_Error, TYPE_ClassCastException);
/**
- * non-null; the list <code>[java.lang.Error,
- * java.lang.NegativeArraySizeException]</code>
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NegativeArraySizeException]}
*/
public static final StdTypeList LIST_Error_NegativeArraySizeException =
StdTypeList.make(TYPE_Error, TYPE_NegativeArraySizeException);
/**
- * non-null; the list <code>[java.lang.Error,
- * java.lang.NullPointerException]</code>
+ * {@code non-null;} the list {@code [java.lang.Error,
+ * java.lang.NullPointerException]}
*/
public static final StdTypeList LIST_Error_NullPointerException =
StdTypeList.make(TYPE_Error, TYPE_NullPointerException);
/**
- * non-null; the list <code>[java.lang.Error,
+ * {@code non-null;} the list {@code [java.lang.Error,
* java.lang.NullPointerException,
- * java.lang.ArrayIndexOutOfBoundsException]</code>
+ * java.lang.ArrayIndexOutOfBoundsException]}
*/
public static final StdTypeList LIST_Error_Null_ArrayIndexOutOfBounds =
StdTypeList.make(TYPE_Error,
@@ -102,10 +102,10 @@
TYPE_ArrayIndexOutOfBoundsException);
/**
- * non-null; the list <code>[java.lang.Error,
+ * {@code non-null;} the list {@code [java.lang.Error,
* java.lang.NullPointerException,
* java.lang.ArrayIndexOutOfBoundsException,
- * java.lang.ArrayStoreException]</code>
+ * java.lang.ArrayStoreException]}
*/
public static final StdTypeList LIST_Error_Null_ArrayIndex_ArrayStore =
StdTypeList.make(TYPE_Error,
@@ -114,9 +114,9 @@
TYPE_ArrayStoreException);
/**
- * non-null; the list <code>[java.lang.Error,
+ * {@code non-null;} the list {@code [java.lang.Error,
* java.lang.NullPointerException,
- * java.lang.IllegalMonitorStateException]</code>
+ * java.lang.IllegalMonitorStateException]}
*/
public static final StdTypeList
LIST_Error_Null_IllegalMonitorStateException =
diff --git a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
index 3798afb..0fc7d2b 100644
--- a/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
+++ b/dx/src/com/android/dx/rop/code/FillArrayDataInsn.java
@@ -42,11 +42,11 @@
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param sources non-null; specs for all the sources
- * @param initValues non-null; list of initial values to fill the array
- * @param cst non-null; type of the new array
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param sources {@code non-null;} specs for all the sources
+ * @param initValues {@code non-null;} list of initial values to fill the array
+ * @param cst {@code non-null;} type of the new array
*/
public FillArrayDataInsn(Rop opcode, SourcePosition position,
RegisterSpecList sources,
@@ -71,7 +71,7 @@
/**
* Return the list of init values
- * @return non-null; list of init values
+ * @return {@code non-null;} list of init values
*/
public ArrayList<Constant> getInitValues() {
return initValues;
@@ -79,7 +79,7 @@
/**
* Return the type of the newly created array
- * @return non-null; array type
+ * @return {@code non-null;} array type
*/
public Constant getConstant() {
return arrayType;
diff --git a/dx/src/com/android/dx/rop/code/Insn.java b/dx/src/com/android/dx/rop/code/Insn.java
index b1ad0ad..77ab9c0 100644
--- a/dx/src/com/android/dx/rop/code/Insn.java
+++ b/dx/src/com/android/dx/rop/code/Insn.java
@@ -30,25 +30,25 @@
* information.
*/
public abstract class Insn implements ToHuman {
- /** non-null; opcode */
+ /** {@code non-null;} opcode */
private final Rop opcode;
- /** non-null; source position */
+ /** {@code non-null;} source position */
private final SourcePosition position;
- /** null-ok; spec for the result of this instruction, if any */
+ /** {@code null-ok;} spec for the result of this instruction, if any */
private final RegisterSpec result;
- /** non-null; specs for all the sources of this instruction */
+ /** {@code non-null;} specs for all the sources of this instruction */
private final RegisterSpecList sources;
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param result null-ok; spec for the result, if any
- * @param sources non-null; specs for all the sources
+ * @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
+ * @param sources {@code non-null;} specs for all the sources
*/
public Insn(Rop opcode, SourcePosition position, RegisterSpec result,
RegisterSpecList sources) {
@@ -74,7 +74,7 @@
* {@inheritDoc}
*
* Instances of this class compare by identity. That is,
- * <code>x.equals(y)</code> is only true if <code>x == y</code>.
+ * {@code x.equals(y)} is only true if {@code x == y}.
*/
@Override
public final boolean equals(Object other) {
@@ -102,7 +102,7 @@
/**
* Gets a human-oriented (and slightly lossy) string for this instance.
*
- * @return non-null; the human string form
+ * @return {@code non-null;} the human string form
*/
public String toHuman() {
return toHumanWithInline(getInlineString());
@@ -112,7 +112,7 @@
* Gets an "inline" string portion for toHuman(), if available. This
* is the portion that appears after the Rop opcode
*
- * @return null-ok; if non-null, the inline text for toHuman()
+ * @return {@code null-ok;} if non-null, the inline text for toHuman()
*/
public String getInlineString() {
return null;
@@ -121,7 +121,7 @@
/**
* Gets the opcode.
*
- * @return non-null; the opcode
+ * @return {@code non-null;} the opcode
*/
public final Rop getOpcode() {
return opcode;
@@ -130,17 +130,17 @@
/**
* Gets the source position.
*
- * @return non-null; the source position
+ * @return {@code non-null;} the source position
*/
public final SourcePosition getPosition() {
return position;
}
/**
- * Gets the result spec, if any. A return value of <code>null</code>
+ * Gets the result spec, if any. A return value of {@code null}
* means this instruction returns nothing.
*
- * @return null-ok; the result spec, if any
+ * @return {@code null-ok;} the result spec, if any
*/
public final RegisterSpec getResult() {
return result;
@@ -149,10 +149,10 @@
/**
* Gets the spec of a local variable assignment that occurs at this
* instruction, or null if no local variable assignment occurs. This
- * may be the result register, or for <code>mark-local</code> insns
+ * may be the result register, or for {@code mark-local} insns
* it may be the source.
*
- * @return null-ok; a named register spec or null
+ * @return {@code null-ok;} a named register spec or null
*/
public final RegisterSpec getLocalAssignment() {
RegisterSpec assignment;
@@ -178,7 +178,7 @@
/**
* Gets the source specs.
*
- * @return non-null; the source specs
+ * @return {@code non-null;} the source specs
*/
public final RegisterSpecList getSources() {
return sources;
@@ -186,9 +186,9 @@
/**
* Gets whether this instruction can possibly throw an exception. This
- * is just a convenient wrapper for <code>getOpcode().canThrow()</code>.
+ * is just a convenient wrapper for {@code getOpcode().canThrow()}.
*
- * @return <code>true</code> iff this instruction can possibly throw
+ * @return {@code true} iff this instruction can possibly throw
*/
public final boolean canThrow() {
return opcode.canThrow();
@@ -202,7 +202,7 @@
* exceptions. To determine whether this instruction can throw,
* use {@link #canThrow}.
*
- * @return non-null; the catches list
+ * @return {@code non-null;} the catches list
*/
public abstract TypeList getCatches();
@@ -210,7 +210,7 @@
* Calls the appropriate method on the given visitor, depending on the
* class of this instance. Subclasses must override this.
*
- * @param visitor non-null; the visitor to call on
+ * @param visitor {@code non-null;} the visitor to call on
*/
public abstract void accept(Visitor visitor);
@@ -221,8 +221,8 @@
* throw. To determine whether this instruction can throw, use
* {@link #canThrow}.
*
- * @param type non-null; type to append to the catch list
- * @return non-null; an appropriately-constructed instance
+ * @param type {@code non-null;} type to append to the catch list
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public abstract Insn withAddedCatch(Type type);
@@ -231,7 +231,7 @@
* register references have been offset by the given delta.
*
* @param delta the amount to offset register references by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public abstract Insn withRegisterOffset(int delta);
@@ -239,10 +239,10 @@
* Returns an instance that is just like this one, except that, if
* possible, the insn is converted into a version in which the last
* source (if it is a constant) is represented directly rather than
- * as a register reference. <code>this</code> is returned in cases where
+ * as a register reference. {@code this} is returned in cases where
* the translation is not possible.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public Insn withLastSourceLiteral() {
return this;
@@ -251,7 +251,7 @@
/**
* Returns an exact copy of this Insn
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public Insn copy() {
return withRegisterOffset(0);
@@ -270,8 +270,8 @@
}
/**
- * Compares Insn contents, since <code>Insn.equals()</code> is defined
- * to be an identity compare. Insn's are <code>contentEquals()</code>
+ * Compares Insn contents, since {@code Insn.equals()} is defined
+ * to be an identity compare. Insn's are {@code contentEquals()}
* if they have the same opcode, registers, source position, and other
* metadata.
*
@@ -290,9 +290,9 @@
* Returns an instance that is just like this one, except
* with new result and source registers.
*
- * @param result null-ok; new result register
- * @param sources non-null; new sources registers
- * @return non-null; an appropriately-constructed instance
+ * @param result {@code null-ok;} new result register
+ * @param sources {@code non-null;} new sources registers
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public abstract Insn withNewRegisters(RegisterSpec result,
RegisterSpecList sources);
@@ -301,8 +301,8 @@
* Returns the string form of this instance, with the given bit added in
* the standard location for an inline argument.
*
- * @param extra null-ok; the inline argument string
- * @return non-null; the string form
+ * @param extra {@code null-ok;} the inline argument string
+ * @return {@code non-null;} the string form
*/
protected final String toStringWithInline(String extra) {
StringBuffer sb = new StringBuffer(80);
@@ -334,8 +334,8 @@
* Returns the human string form of this instance, with the given
* bit added in the standard location for an inline argument.
*
- * @param extra null-ok; the inline argument string
- * @return non-null; the human string form
+ * @param extra {@code null-ok;} the inline argument string
+ * @return {@code non-null;} the human string form
*/
protected final String toHumanWithInline(String extra) {
StringBuffer sb = new StringBuffer(80);
@@ -380,42 +380,42 @@
/**
* Visits a {@link PlainInsn}.
*
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitPlainInsn(PlainInsn insn);
/**
* Visits a {@link PlainCstInsn}.
*
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitPlainCstInsn(PlainCstInsn insn);
/**
* Visits a {@link SwitchInsn}.
*
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitSwitchInsn(SwitchInsn insn);
/**
* Visits a {@link ThrowingCstInsn}.
*
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitThrowingCstInsn(ThrowingCstInsn insn);
/**
* Visits a {@link ThrowingInsn}.
*
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitThrowingInsn(ThrowingInsn insn);
/**
* Visits a {@link FillArrayDataInsn}.
*
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitFillArrayDataInsn(FillArrayDataInsn insn);
}
diff --git a/dx/src/com/android/dx/rop/code/InsnList.java b/dx/src/com/android/dx/rop/code/InsnList.java
index 34f124c..493f7fc 100644
--- a/dx/src/com/android/dx/rop/code/InsnList.java
+++ b/dx/src/com/android/dx/rop/code/InsnList.java
@@ -24,7 +24,7 @@
public final class InsnList
extends FixedSizeList {
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -35,10 +35,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Insn get(int n) {
return (Insn) get0(n);
@@ -47,8 +47,8 @@
/**
* Sets the instruction at the given index.
*
- * @param n >= 0, < size(); which index
- * @param insn non-null; the instruction to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param insn {@code non-null;} the instruction to set at {@code n}
*/
public void set(int n, Insn insn) {
set0(n, insn);
@@ -56,9 +56,9 @@
/**
* Gets the last instruction. This is just a convenient shorthand for
- * <code>get(size() - 1)</code>.
+ * {@code get(size() - 1)}.
*
- * @return non-null; the last instruction
+ * @return {@code non-null;} the last instruction
*/
public Insn getLast() {
return get(size() - 1);
@@ -67,7 +67,7 @@
/**
* Visits each instruction in the list, in order.
*
- * @param visitor non-null; visitor to use
+ * @param visitor {@code non-null;} visitor to use
*/
public void forEach(Insn.Visitor visitor) {
int sz = size();
@@ -78,9 +78,9 @@
}
/**
- * Compares the contents of this <code>InsnList</code> with another.
+ * Compares the contents of this {@code InsnList} with another.
* The blocks must have the same number of insns, and each Insn must
- * also return true to <code>Insn.contentEquals()</code>.
+ * also return true to {@code Insn.contentEquals()}.
*
* @param b to compare
* @return true in the case described above.
@@ -108,7 +108,7 @@
* original.
*
* @param delta the amount to offset register numbers by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public InsnList withRegisterOffset(int delta) {
int sz = size();
diff --git a/dx/src/com/android/dx/rop/code/LocalItem.java b/dx/src/com/android/dx/rop/code/LocalItem.java
index bac6ce2..7d6bebe 100644
--- a/dx/src/com/android/dx/rop/code/LocalItem.java
+++ b/dx/src/com/android/dx/rop/code/LocalItem.java
@@ -22,10 +22,10 @@
* A local variable item: either a name or a signature or both.
*/
public class LocalItem implements Comparable<LocalItem> {
- /** null-ok; local variable name */
+ /** {@code null-ok;} local variable name */
private final CstUtf8 name;
- /** null-ok; local variable signature */
+ /** {@code null-ok;} local variable signature */
private final CstUtf8 signature;
/**
@@ -33,9 +33,9 @@
*
* TODO: intern these
*
- * @param name null-ok; local variable name
- * @param signature null-ok; local variable signature
- * @return non-null; appropriate instance.
+ * @param name {@code null-ok;} local variable name
+ * @param signature {@code null-ok;} local variable signature
+ * @return {@code non-null;} appropriate instance.
*/
public static LocalItem make(CstUtf8 name, CstUtf8 signature) {
if (name == null && signature == null) {
@@ -48,8 +48,8 @@
/**
* Constructs instance.
*
- * @param name null-ok; local variable name
- * @param signature null-ok; local variable signature
+ * @param name {@code null-ok;} local variable name
+ * @param signature {@code null-ok;} local variable signature
*/
private LocalItem(CstUtf8 name, CstUtf8 signature) {
this.name = name;
@@ -126,7 +126,7 @@
/**
* Gets name.
*
- * @return null-ok; name
+ * @return {@code null-ok;} name
*/
public CstUtf8 getName() {
return name;
@@ -135,7 +135,7 @@
/**
* Gets signature.
*
- * @return null-ok; signature
+ * @return {@code null-ok;} signature
*/
public CstUtf8 getSignature() {
return signature;
diff --git a/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java b/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
index 2d4cbce..db142c2 100644
--- a/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
+++ b/dx/src/com/android/dx/rop/code/LocalVariableExtractor.java
@@ -24,23 +24,23 @@
* a method.
*/
public final class LocalVariableExtractor {
- /** non-null; method being extracted from */
+ /** {@code non-null;} method being extracted from */
private final RopMethod method;
- /** non-null; block list for the method */
+ /** {@code non-null;} block list for the method */
private final BasicBlockList blocks;
- /** non-null; result in-progress */
+ /** {@code non-null;} result in-progress */
private final LocalVariableInfo resultInfo;
- /** non-null; work set indicating blocks needing to be processed */
+ /** {@code non-null;} work set indicating blocks needing to be processed */
private final int[] workSet;
/**
* Extracts out all the local variable information from the given method.
*
- * @param method non-null; the method to extract from
- * @return non-null; the extracted information
+ * @param method {@code non-null;} the method to extract from
+ * @return {@code non-null;} the extracted information
*/
public static LocalVariableInfo extract(RopMethod method) {
LocalVariableExtractor lve = new LocalVariableExtractor(method);
@@ -50,7 +50,7 @@
/**
* Constructs an instance. This method is private. Use {@link #extract}.
*
- * @param method non-null; the method to extract from
+ * @param method {@code non-null;} the method to extract from
*/
private LocalVariableExtractor(RopMethod method) {
if (method == null) {
@@ -69,7 +69,7 @@
/**
* Does the extraction.
*
- * @return non-null; the extracted information
+ * @return {@code non-null;} the extracted information
*/
private LocalVariableInfo doit() {
for (int label = method.getFirstLabel();
@@ -86,7 +86,7 @@
/**
* Processes a single block.
*
- * @param label >= 0; label of the block to process
+ * @param label {@code >= 0;} label of the block to process
*/
private void processBlock(int label) {
RegisterSpecSet primaryState = resultInfo.mutableCopyOfStarts(label);
@@ -101,7 +101,6 @@
* state *before* executing it to be what is merged into
* exception targets.
*/
- Insn lastInsn = insns.getLast();
boolean canThrowDuringLastInsn = block.hasExceptionHandlers() &&
(insns.getLast().getResult() != null);
int freezeSecondaryStateAt = insnSz - 1;
diff --git a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
index 29c239b..fa5e7cc 100644
--- a/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
+++ b/dx/src/com/android/dx/rop/code/LocalVariableInfo.java
@@ -27,30 +27,30 @@
*/
public final class LocalVariableInfo
extends MutabilityControl {
- /** >= 0; the register count for the method */
+ /** {@code >= 0;} the register count for the method */
private final int regCount;
/**
- * non-null; {@link RegisterSpecSet} to use when indicating a block
+ * {@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
*/
private final RegisterSpecSet emptySet;
/**
- * non-null; array consisting of register sets representing the
+ * {@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
*/
private final RegisterSpecSet[] blockStarts;
- /** non-null; map from instructions to the variable each assigns */
+ /** {@code non-null;} map from instructions to the variable each assigns */
private final HashMap<Insn, RegisterSpec> insnAssignments;
/**
* Constructs an instance.
*
- * @param method non-null; the method being represented by this instance
+ * @param method {@code non-null;} the method being represented by this instance
*/
public LocalVariableInfo(RopMethod method) {
if (method == null) {
@@ -73,8 +73,8 @@
* Sets the register set associated with the start of the block with
* the given label.
*
- * @param label >= 0; the block label
- * @param specs non-null; the register set to associate with the block
+ * @param label {@code >= 0;} the block label
+ * @param specs {@code non-null;} the register set to associate with the block
*/
public void setStarts(int label, RegisterSpecSet specs) {
throwIfImmutable();
@@ -98,12 +98,12 @@
* merge the two sets and call {@link #setStarts} on the result of the
* merge.
*
- * @param label >= 0; the block label
- * @param specs non-null; the register set to merge into the start set
+ * @param label {@code >= 0;} the block label
+ * @param specs {@code non-null;} the register set to merge into the start set
* for the block
- * @return <code>true</code> if the merge resulted in an actual change
+ * @return {@code true} if the merge resulted in an actual change
* to the associated set (including storing one for the first time) or
- * <code>false</code> if there was no change
+ * {@code false} if there was no change
*/
public boolean mergeStarts(int label, RegisterSpecSet specs) {
RegisterSpecSet start = getStarts0(label);
@@ -132,8 +132,8 @@
* 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 >= 0; the block label
- * @return non-null; the associated register set
+ * @param label {@code >= 0;} the block label
+ * @return {@code non-null;} the associated register set
*/
public RegisterSpecSet getStarts(int label) {
RegisterSpecSet result = getStarts0(label);
@@ -144,10 +144,10 @@
/**
* Gets the register set associated with the start of the given
* block. This is just convenient shorthand for
- * <code>getStarts(block.getLabel())</code>.
+ * {@code getStarts(block.getLabel())}.
*
- * @param block non-null; the block in question
- * @return non-null; the associated register set
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the associated register set
*/
public RegisterSpecSet getStarts(BasicBlock block) {
return getStarts(block.getLabel());
@@ -159,8 +159,8 @@
* newly-allocated empty {@link RegisterSpecSet} of appropriate
* max size if there is not yet any set associated with the block.
*
- * @param label >= 0; the block label
- * @return non-null; the associated register set
+ * @param label {@code >= 0;} the block label
+ * @return {@code non-null;} the associated register set
*/
public RegisterSpecSet mutableCopyOfStarts(int label) {
RegisterSpecSet result = getStarts0(label);
@@ -180,8 +180,8 @@
* simple type and the one in the instruction can be an arbitrary
* {@link TypeBearer} (such as a constant value).
*
- * @param insn non-null; the instruction in question
- * @param spec non-null; the associated register spec
+ * @param insn {@code non-null;} the instruction in question
+ * @param spec {@code non-null;} the associated register spec
*/
public void addAssignment(Insn insn, RegisterSpec spec) {
throwIfImmutable();
@@ -201,8 +201,8 @@
* Gets the named register being assigned by the given instruction, if
* previously stored in this instance.
*
- * @param insn non-null; instruction in question
- * @return null-ok; the named register being assigned, if any
+ * @param insn {@code non-null;} instruction in question
+ * @return {@code null-ok;} the named register being assigned, if any
*/
public RegisterSpec getAssignment(Insn insn) {
return insnAssignments.get(insn);
@@ -211,7 +211,7 @@
/**
* Gets the number of assignments recorded by this instance.
*
- * @return >= 0; the number of assignments
+ * @return {@code >= 0;} the number of assignments
*/
public int getAssignmentCount() {
return insnAssignments.size();
@@ -235,8 +235,8 @@
* Helper method, to get the starts for a label, throwing the
* right exception for range problems.
*
- * @param label >= 0; the block label
- * @return null-ok; associated register set or <code>null</code> if there
+ * @param label {@code >= 0;} the block label
+ * @return {@code null-ok;} associated register set or {@code null} if there
* is none
*/
private RegisterSpecSet getStarts0(int label) {
diff --git a/dx/src/com/android/dx/rop/code/PlainCstInsn.java b/dx/src/com/android/dx/rop/code/PlainCstInsn.java
index 908b3cb..7a3ac38 100644
--- a/dx/src/com/android/dx/rop/code/PlainCstInsn.java
+++ b/dx/src/com/android/dx/rop/code/PlainCstInsn.java
@@ -30,11 +30,11 @@
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param result null-ok; spec for the result, if any
- * @param sources non-null; specs for all the sources
- * @param cst non-null; the constant
+ * @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
+ * @param sources {@code non-null;} specs for all the sources
+ * @param cst {@code non-null;} the constant
*/
public PlainCstInsn(Rop opcode, SourcePosition position,
RegisterSpec result, RegisterSpecList sources,
diff --git a/dx/src/com/android/dx/rop/code/PlainInsn.java b/dx/src/com/android/dx/rop/code/PlainInsn.java
index 4c5c9b7..d1db646 100644
--- a/dx/src/com/android/dx/rop/code/PlainInsn.java
+++ b/dx/src/com/android/dx/rop/code/PlainInsn.java
@@ -31,10 +31,10 @@
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param result null-ok; spec for the result, if any
- * @param sources non-null; specs for all the sources
+ * @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
+ * @param sources {@code non-null;} specs for all the sources
*/
public PlainInsn(Rop opcode, SourcePosition position,
RegisterSpec result, RegisterSpecList sources) {
@@ -57,10 +57,10 @@
/**
* Constructs a single-source instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param result null-ok; spec for the result, if any
- * @param source non-null; spec for the source
+ * @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
+ * @param source {@code non-null;} spec for the source
*/
public PlainInsn(Rop opcode, SourcePosition position, RegisterSpec result,
RegisterSpec source) {
diff --git a/dx/src/com/android/dx/rop/code/RegOps.java b/dx/src/com/android/dx/rop/code/RegOps.java
index f201f68..2084a69 100644
--- a/dx/src/com/android/dx/rop/code/RegOps.java
+++ b/dx/src/com/android/dx/rop/code/RegOps.java
@@ -21,283 +21,279 @@
/**
* All the register-based opcodes, and related utilities.
*
- * <p><b>Note:</b> Opcode descriptions use a rough pseudocode. <code>r</code>
- * is the result register, <code>x</code> is the first argument,
- * <code>y</code> is the second argument, and <code>z</code> is the
+ * <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
* third argument. The expression which describes
* the operation uses Java-ish syntax but is preceded by type indicators for
* each of the values.
*/
public final class RegOps {
- /** <code>nop()</code> */
+ /** {@code nop()} */
public static final int NOP = 1;
- /** <code>T: any type; r,x: T :: r = x;</code> */
+ /** {@code T: any type; r,x: T :: r = x;} */
public static final int MOVE = 2;
- /** <code>T: any type; r,param(x): T :: r = param(x)</code> */
+ /** {@code T: any type; r,param(x): T :: r = param(x)} */
public static final int MOVE_PARAM = 3;
/**
- * <code>T: Throwable; r: T :: r = caught_exception</code>.
+ * {@code T: Throwable; r: T :: r = caught_exception}.
* <b>Note:</b> This opcode should only ever be used in the
* first instruction of a block, and such blocks must be
* the start of an exception handler.
*/
public static final int MOVE_EXCEPTION = 4;
- /** <code>T: any type; r, literal: T :: r = literal;</code> */
+ /** {@code T: any type; r, literal: T :: r = literal;} */
public static final int CONST = 5;
- /** <code>goto <i>label</i></code> */
+ /** {@code goto label} */
public static final int GOTO = 6;
/**
- * <code>T: int or Object; x,y: T :: if (x == y) goto
- * <i>label</i></code>
+ * {@code T: int or Object; x,y: T :: if (x == y) goto
+ * label}
*/
public static final int IF_EQ = 7;
/**
- * <code>T: int or Object; x,y: T :: if (x != y) goto
- * <i>label</i></code>
+ * {@code T: int or Object; x,y: T :: if (x != y) goto
+ * label}
*/
public static final int IF_NE = 8;
- /** <code>x,y: int :: if (x < y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x < y) goto label} */
public static final int IF_LT = 9;
- /** <code>x,y: int :: if (x >= y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x >= y) goto label} */
public static final int IF_GE = 10;
- /** <code>x,y: int :: if (x <= y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x <= y) goto label} */
public static final int IF_LE = 11;
- /** <code>x,y: int :: if (x > y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x > y) goto label} */
public static final int IF_GT = 12;
- /** <code>x: int :: goto <i>table[x]</i></code> */
+ /** {@code x: int :: goto table[x]} */
public static final int SWITCH = 13;
- /** <code>T: any numeric type; r,x,y: T :: r = x + y</code> */
+ /** {@code T: any numeric type; r,x,y: T :: r = x + y} */
public static final int ADD = 14;
- /** <code>T: any numeric type; r,x,y: T :: r = x - y</code> */
+ /** {@code T: any numeric type; r,x,y: T :: r = x - y} */
public static final int SUB = 15;
- /** <code>T: any numeric type; r,x,y: T :: r = x * y</code> */
+ /** {@code T: any numeric type; r,x,y: T :: r = x * y} */
public static final int MUL = 16;
- /** <code>T: any numeric type; r,x,y: T :: r = x / y</code> */
+ /** {@code T: any numeric type; r,x,y: T :: r = x / y} */
public static final int DIV = 17;
/**
- * <code>T: any numeric type; r,x,y: T :: r = x % y</code>
+ * {@code T: any numeric type; r,x,y: T :: r = x % y}
* (Java-style remainder)
*/
public static final int REM = 18;
- /** <code>T: any numeric type; r,x: T :: r = -x</code> */
+ /** {@code T: any numeric type; r,x: T :: r = -x} */
public static final int NEG = 19;
- /** <code>T: any integral type; r,x,y: T :: r = x & y</code> */
+ /** {@code T: any integral type; r,x,y: T :: r = x & y} */
public static final int AND = 20;
- /** <code>T: any integral type; r,x,y: T :: r = x | y</code> */
+ /** {@code T: any integral type; r,x,y: T :: r = x | y} */
public static final int OR = 21;
- /** <code>T: any integral type; r,x,y: T :: r = x ^ y</code> */
+ /** {@code T: any integral type; r,x,y: T :: r = x ^ y} */
public static final int XOR = 22;
/**
- * <code>T: any integral type; r,x: T; y: int :: r = x <<
- * y</code>
+ * {@code T: any integral type; r,x: T; y: int :: r = x << y}
*/
public static final int SHL = 23;
/**
- * <code>T: any integral type; r,x: T; y: int :: r = x >>
- * y</code> (signed right-shift)
+ * {@code T: any integral type; r,x: T; y: int :: r = x >> y}
+ * (signed right-shift)
*/
public static final int SHR = 24;
/**
- * <code>T: any integral type; r,x: T; y: int :: r = x
- * >>> y</code> (unsigned right-shift)
+ * {@code T: any integral type; r,x: T; y: int :: r = x >>> y}
+ * (unsigned right-shift)
*/
public static final int USHR = 25;
- /** <code>T: any integral type; r,x: T :: r = ~x</code> */
+ /** {@code T: any integral type; r,x: T :: r = ~x} */
public static final int NOT = 26;
/**
- * <code>T: any numeric type; r: int; x,y: T :: r = (x == y) ? 0
- * : (x > y) ? 1 : -1</code> (Java-style "cmpl" where a NaN is
+ * {@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)
*/
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</code> (Java-style "cmpg" where a NaN is
+ * {@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)
*/
public static final int CMPG = 28;
/**
- * <code>T: any numeric type; U: any numeric type; r: T; x: U ::
- * r = (T) x</code> (numeric type conversion between the four
+ * {@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)
*/
public static final int CONV = 29;
/**
- * <code>r,x: int :: r = (x << 24) >> 24</code> (Java-style
+ * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
* convert int to byte)
*/
public static final int TO_BYTE = 30;
/**
- * <code>r,x: int :: r = x & 0xffff</code> (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</code> (Java-style
+ * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
* convert int to short)
*/
public static final int TO_SHORT = 32;
- /** <code>T: return type for the method; x: T; return x</code> */
+ /** {@code T: return type for the method; x: T; return x} */
public static final int RETURN = 33;
- /** <code>T: any type; r: int; x: T[]; :: r = x.length</code> */
+ /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
public static final int ARRAY_LENGTH = 34;
- /** <code>x: Throwable :: throw(x)</code> */
+ /** {@code x: Throwable :: throw(x)} */
public static final int THROW = 35;
- /** <code>x: Object :: monitorenter(x)</code> */
+ /** {@code x: Object :: monitorenter(x)} */
public static final int MONITOR_ENTER = 36;
- /** <code>x: Object :: monitorexit(x)</code> */
+ /** {@code x: Object :: monitorexit(x)} */
public static final int MONITOR_EXIT = 37;
- /** <code>T: any type; r: T; x: T[]; y: int :: r = x[y]</code> */
+ /** {@code T: any type; r: T; x: T[]; y: int :: r = x[y]} */
public static final int AGET = 38;
- /** <code>T: any type; x: T; y: T[]; z: int :: x[y] = z</code> */
+ /** {@code T: any type; x: T; y: T[]; z: int :: x[y] = z} */
public static final int APUT = 39;
/**
- * <code>T: any non-array object type :: r =
- * alloc(T)</code> (allocate heap space for an object)
+ * {@code T: any non-array object type :: r =
+ * alloc(T)} (allocate heap space for an object)
*/
public static final int NEW_INSTANCE = 40;
- /** <code>T: any array type; r: T; x: int :: r = new T[x]</code> */
+ /** {@code T: any array type; r: T; x: int :: r = new T[x]} */
public static final int NEW_ARRAY = 41;
/**
- * <code>T: any array type; r: T; x: int; v0..vx: T :: r = new T[x]
- * {v0, ..., vx}</code>
+ * {@code T: any array type; r: T; x: int; v0..vx: T :: r = new T[x]
+ * {v0, ..., vx}}
*/
public static final int FILLED_NEW_ARRAY = 42;
/**
- * <code>T: any object type; x: Object :: (T) x</code> (can
- * throw <code>ClassCastException</code>)
+ * {@code T: any object type; x: Object :: (T) x} (can
+ * throw {@code ClassCastException})
*/
public static final int CHECK_CAST = 43;
/**
- * <code>T: any object type; x: Object :: x instanceof
- * T</code>
+ * {@code T: any object type; x: Object :: x instanceof T}
*/
public static final int INSTANCE_OF = 44;
/**
- * <code>T: any type; r: T; x: Object; f: instance field spec of
- * type T :: r = x.f</code>
+ * {@code T: any type; r: T; x: Object; f: instance field spec of
+ * type T :: r = x.f}
*/
public static final int GET_FIELD = 45;
/**
- * <code>T: any type; r: T; f: static field spec of type T :: r =
- * f</code>
+ * {@code T: any type; r: T; f: static field spec of type T :: r =
+ * 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</code>
+ * {@code T: any type; x: T; y: Object; f: instance field spec of type
+ * T :: y.f = x}
*/
public static final int PUT_FIELD = 47;
/**
- * <code>T: any type; f: static field spec of type T; x: T :: f =
- * x</code>
+ * {@code T: any type; f: static field spec of type T; x: T :: f = x}
*/
public static final int PUT_STATIC = 48;
/**
- * <code>Tr, T0, T1...: any types; r: Tr; m: static method spec;
- * y0: T0; y1: T1 ... :: r = m(y0, y1, ...)</code> (call static
+ * {@code Tr, T0, T1...: any types; r: Tr; m: static method spec;
+ * y0: T0; y1: T1 ... :: r = m(y0, y1, ...)} (call static
* 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, ...)</code> (call normal
+ * {@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)
*/
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, ...)</code> (call
+ * {@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)
*/
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, ...)</code> (call
+ * {@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)
*/
public static final int INVOKE_DIRECT = 52;
/**
- * <code>Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
+ * {@code Tr, T0, T1...: any types; r: Tr; x: Object; m: interface
* (instance) method spec; y0: T0; y1: T1 ... :: r = x.m(y0, y1,
- * ...)</code> (call interface method)
+ * ...)} (call interface method)
*/
public static final int INVOKE_INTERFACE = 53;
/**
- * <code> T0: any type; </code> (mark beginning or end of local variable
- * name
+ * {@code T0: any type; name: local variable name :: mark(name,T0)}
+ * (mark beginning or end of local variable name)
*/
public static final int MARK_LOCAL = 54;
/**
- * <code>T: Any type; r: T :: r = return_type</code>.
+ * {@code T: Any type; r: T :: r = return_type}.
* <b>Note:</b> This opcode should only ever be used in the
* first instruction of a block following an invoke-*.
*/
public static final int MOVE_RESULT = 55;
/**
- * <code>T: Any type; r: T :: r = return_type</code>.
+ * {@code T: Any type; r: T :: r = return_type}.
* <b>Note:</b> This opcode should only ever be used in the
* first instruction of a block following a non-invoke throwing insn
*/
public static final int MOVE_RESULT_PSEUDO = 56;
- /** <code>T: Any primitive type; v0..vx: T :: {v0, ..., vx}</code> */
+ /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
public static final int FILL_ARRAY_DATA = 57;
/**
@@ -310,8 +306,8 @@
/**
* Gets the name of the given opcode.
*
- * @param opcode >= 0, <= 255; the opcode
- * @return non-null; its name
+ * @param opcode {@code >= 0, <= 255;} the opcode
+ * @return {@code non-null;} its name
*/
public static String opName(int opcode) {
switch (opcode) {
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpec.java b/dx/src/com/android/dx/rop/code/RegisterSpec.java
index 73af91f..1f14767 100644
--- a/dx/src/com/android/dx/rop/code/RegisterSpec.java
+++ b/dx/src/com/android/dx/rop/code/RegisterSpec.java
@@ -30,33 +30,33 @@
*/
public final class RegisterSpec
implements TypeBearer, ToHuman, Comparable<RegisterSpec> {
- /** non-null; string to prefix register numbers with */
+ /** {@code non-null;} string to prefix register numbers with */
public static final String PREFIX = "v";
- /** non-null; intern table for instances */
+ /** {@code non-null;} intern table for instances */
private static final HashMap<Object, RegisterSpec> theInterns =
new HashMap<Object, RegisterSpec>(1000);
- /** non-null; common comparison instance used while interning */
+ /** {@code non-null;} common comparison instance used while interning */
private static final ForComparison theInterningItem = new ForComparison();
- /** >= 0; register number */
+ /** {@code >= 0;} register number */
private final int reg;
- /** non-null; type loaded or stored */
+ /** {@code non-null;} type loaded or stored */
private final TypeBearer type;
- /** null-ok; local variable info associated with this register, if any */
+ /** {@code null-ok;} local variable info associated with this register, if any */
private final LocalItem local;
/**
* Intern the given triple as an instance of this class.
*
- * @param reg >= 0; the register number
- * @param type non-null; the type (or possibly actual value) which
+ * @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
- * @param local null-ok; the associated local variable, if any
- * @return non-null; an appropriately-constructed instance
+ * @param local {@code null-ok;} the associated local variable, if any
+ * @return {@code non-null;} an appropriately-constructed instance
*/
private static RegisterSpec intern(int reg, TypeBearer type,
LocalItem local) {
@@ -77,10 +77,10 @@
* no variable info. This method is allowed to return shared
* instances (but doesn't necessarily do so).
*
- * @param reg >= 0; the register number
- * @param type non-null; the type (or possibly actual value) which
+ * @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
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static RegisterSpec make(int reg, TypeBearer type) {
return intern(reg, type, null);
@@ -91,11 +91,11 @@
* variable info. This method is allowed to return shared
* instances (but doesn't necessarily do so).
*
- * @param reg >= 0; the register number
- * @param type non-null; the type (or possibly actual value) which
+ * @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
- * @param local non-null; the associated local variable
- * @return non-null; an appropriately-constructed instance
+ * @param local {@code non-null;} the associated local variable
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static RegisterSpec make(int reg, TypeBearer type,
LocalItem local) {
@@ -111,12 +111,12 @@
* variable info. This method is allowed to return shared
* instances (but doesn't necessarily do so).
*
- * @param reg >= 0; the register number
- * @param type non-null; the type (or possibly actual value) which
+ * @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
- * @param local null-ok; the associated variable info or null for
+ * @param local {@code null-ok;} the associated variable info or null for
* none
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static RegisterSpec makeLocalOptional(
int reg, TypeBearer type, LocalItem local) {
@@ -127,8 +127,8 @@
/**
* Gets the string form for the given register number.
*
- * @param reg >= 0; the register number
- * @return non-null; the string form
+ * @param reg {@code >= 0;} the register number
+ * @return {@code non-null;} the string form
*/
public static String regString(int reg) {
return PREFIX + reg;
@@ -138,10 +138,10 @@
* Constructs an instance. This constructor is private. Use
* {@link #make}.
*
- * @param reg >= 0; the register number
- * @param type non-null; the type (or possibly actual value) which
+ * @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
- * @param local null-ok; the associated local variable, if any
+ * @param local {@code null-ok;} the associated local variable, if any
*/
private RegisterSpec(int reg, TypeBearer type, LocalItem local) {
if (reg < 0) {
@@ -178,7 +178,7 @@
* to ignore whatever arbitrary extra stuff might be carried around
* by an outer {@link TypeBearer}.
*
- * @param other null-ok; spec to compare to
+ * @param other {@code null-ok;} spec to compare to
* @return {@code true} iff {@code this} and {@code other} are equal
* in the stated way
*/
@@ -195,7 +195,7 @@
* This is useful to determine if two instances refer to the "same"
* local variable.
*
- * @param other null-ok; spec to compare to
+ * @param other {@code null-ok;} spec to compare to
* @return {@code true} iff {@code this} and {@code other} are equal
* in the stated way
*/
@@ -230,8 +230,8 @@
* Compares by (in priority order) register number, unwrapped type
* (that is types not {@link TypeBearer}s, and local info.
*
- * @param other non-null; spec to compare to
- * @return {@code -1..1}; standard result of comparison
+ * @param other {@code non-null;} spec to compare to
+ * @return {@code -1..1;} standard result of comparison
*/
public int compareTo(RegisterSpec other) {
if (this.reg < other.reg) {
@@ -316,7 +316,7 @@
/**
* Gets the register number.
*
- * @return >= 0; the register number
+ * @return {@code >= 0;} the register number
*/
public int getReg() {
return reg;
@@ -326,7 +326,7 @@
* Gets the type (or actual value) which is loaded from or stored
* to the register associated with this instance.
*
- * @return non-null; the type
+ * @return {@code non-null;} the type
*/
public TypeBearer getTypeBearer() {
return type;
@@ -335,7 +335,7 @@
/**
* Gets the variable info associated with this instance, if any.
*
- * @return null-ok; the variable info, or <code>null</code> if this
+ * @return {@code null-ok;} the variable info, or {@code null} if this
* instance has none
*/
public LocalItem getLocalItem() {
@@ -349,7 +349,7 @@
* be used to determine the minimum required register count
* implied by this instance.
*
- * @return >= 0; the required registers size
+ * @return {@code >= 0;} the required registers size
*/
public int getNextReg() {
return reg + getCategory();
@@ -357,11 +357,11 @@
/**
* Gets the category of this instance's type. This is just a convenient
- * shorthand for <code>getType().getCategory()</code>.
+ * shorthand for {@code getType().getCategory()}.
*
* @see #isCategory1
* @see #isCategory2
- * @return 1..2; the category of this instance's type
+ * @return {@code 1..2;} the category of this instance's type
*/
public int getCategory() {
return type.getType().getCategory();
@@ -369,7 +369,7 @@
/**
* Gets whether this instance's type is category 1. This is just a
- * convenient shorthand for <code>getType().isCategory1()</code>.
+ * convenient shorthand for {@code getType().isCategory1()}.
*
* @see #getCategory
* @see #isCategory2
@@ -381,7 +381,7 @@
/**
* Gets whether this instance's type is category 2. This is just a
- * convenient shorthand for <code>getType().isCategory2()</code>.
+ * convenient shorthand for {@code getType().isCategory2()}.
*
* @see #getCategory
* @see #isCategory1
@@ -394,7 +394,7 @@
/**
* Gets the string form for just the register number of this instance.
*
- * @return non-null; the register string form
+ * @return {@code non-null;} the register string form
*/
public String regString() {
return regString(reg);
@@ -405,28 +405,28 @@
* and the given one, if any. The intersection is defined as follows:
*
* <ul>
- * <li>If <code>other</code> is <code>null</code>, then the result
- * is <code>null</code>.
+ * <li>If {@code other} is {@code null}, then the result
+ * is {@code null}.
* <li>If the register numbers don't match, then the intersection
- * is <code>null</code>. Otherwise, the register number of the
+ * is {@code null}. Otherwise, the register number of the
* intersection is the same as the one in the two instances.</li>
- * <li>If the types returned by <code>getType()</code> are not
- * <code>equals()</code>, then the intersection is null.</li>
- * <li>If the type bearers returned by <code>getTypeBearer()</code>
- * are <code>equals()</code>, then the intersection's type bearer
+ * <li>If the types returned by {@code getType()} are not
+ * {@code equals()}, then the intersection is null.</li>
+ * <li>If the type bearers returned by {@code getTypeBearer()}
+ * are {@code equals()}, then the intersection's type bearer
* is the one from this instance. Otherwise, the intersection's
- * type bearer is the <code>getType()</code> of this instance.</li>
- * <li>If the locals are <code>equals()</code>, then the local info
+ * type bearer is the {@code getType()} of this instance.</li>
+ * <li>If the locals are {@code equals()}, then the local info
* of the intersection is the local info of this instance. Otherwise,
- * the local info of the intersection is <code>null</code>.</li>
+ * the local info of the intersection is {@code null}.</li>
* </ul>
*
- * @param other null-ok; instance to intersect with (or <code>null</code>)
+ * @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</code>, then the only non-null
+ * intersection; if {@code true}, then the only non-null
* results occur when registers being intersected have equal local
- * infos (or both have <code>null</code> local infos)
- * @return null-ok; the intersection
+ * infos (or both have {@code null} local infos)
+ * @return {@code null-ok;} the intersection
*/
public RegisterSpec intersect(RegisterSpec other, boolean localPrimary) {
if (this == other) {
@@ -471,8 +471,8 @@
* Returns an instance that is identical to this one, except that the
* register number is replaced by the given one.
*
- * @param newReg >= 0; the new register number
- * @return non-null; an appropriately-constructed instance
+ * @param newReg {@code >= 0;} the new register number
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec withReg(int newReg) {
if (reg == newReg) {
@@ -486,8 +486,8 @@
* Returns an instance that is identical to this one, except that
* the type is replaced by the given one.
*
- * @param newType non-null; the new type
- * @return non-null; an appropriately-constructed instance
+ * @param newType {@code non-null;} the new type
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec withType(TypeBearer newType) {
return makeLocalOptional(reg, newType, local);
@@ -498,7 +498,7 @@
* register number is offset by the given amount.
*
* @param delta the amount to offset the register number by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec withOffset(int delta) {
if (delta == 0) {
@@ -514,7 +514,7 @@
* (thereby stripping off non-type information) with any
* initialization information stripped away as well.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec withSimpleType() {
TypeBearer orig = type;
@@ -541,7 +541,7 @@
* Returns an instance that is identical to this one except that the
* local variable is as specified in the parameter.
*
- * @param local null-ok; the local item or null for none
+ * @param local {@code null-ok;} the local item or null for none
* @return an appropriate instance
*/
public RegisterSpec withLocalItem(LocalItem local) {
@@ -559,7 +559,7 @@
* Helper for {@link #toString} and {@link #toHuman}.
*
* @param human whether to be human-oriented
- * @return non-null; the string form
+ * @return {@code non-null;} the string form
*/
private String toString0(boolean human) {
StringBuffer sb = new StringBuffer(40);
@@ -588,27 +588,31 @@
/**
* Holder of register spec data for the purposes of comparison (so that
- * <code>RegisterSpec</code> itself can still keep <code>final</code>
+ * {@code RegisterSpec} itself can still keep {@code final}
* instance variables.
*/
private static class ForComparison {
- /** >= 0; register number */
+ /** {@code >= 0;} register number */
private int reg;
- /** non-null; type loaded or stored */
+ /** {@code non-null;} type loaded or stored */
private TypeBearer type;
- /** null-ok; local variable associated with this register, if any */
+ /**
+ * {@code null-ok;} local variable associated with this
+ * register, if any
+ */
private LocalItem local;
/**
* Set all the instance variables.
*
- * @param reg >= 0; the register number
- * @param type non-null; the type (or possibly actual value) which
- * is loaded from or stored to the indicated register
- * @param local null-ok; the associated local variable, if any
- * @return non-null; an appropriately-constructed instance
+ * @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
+ * @param local {@code null-ok;} the associated local variable, if any
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public void set(int reg, TypeBearer type, LocalItem local) {
this.reg = reg;
@@ -617,10 +621,10 @@
}
/**
- * Construct a <code>RegisterSpec</code> of this instance's
+ * Construct a {@code RegisterSpec} of this instance's
* contents.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpec toRegisterSpec() {
return new RegisterSpec(reg, type, local);
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecList.java b/dx/src/com/android/dx/rop/code/RegisterSpecList.java
index 28657a1..5a02a8d 100644
--- a/dx/src/com/android/dx/rop/code/RegisterSpecList.java
+++ b/dx/src/com/android/dx/rop/code/RegisterSpecList.java
@@ -25,14 +25,14 @@
*/
public final class RegisterSpecList
extends FixedSizeList implements TypeList {
- /** non-null; no-element instance */
+ /** {@code non-null;} no-element instance */
public static final RegisterSpecList EMPTY = new RegisterSpecList(0);
/**
* Makes a single-element instance.
*
- * @param spec non-null; the element
- * @return non-null; an appropriately-constructed instance
+ * @param spec {@code non-null;} the element
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static RegisterSpecList make(RegisterSpec spec) {
RegisterSpecList result = new RegisterSpecList(1);
@@ -43,9 +43,9 @@
/**
* Makes a two-element instance.
*
- * @param spec0 non-null; the first element
- * @param spec1 non-null; the second element
- * @return non-null; an appropriately-constructed 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
*/
public static RegisterSpecList make(RegisterSpec spec0,
RegisterSpec spec1) {
@@ -58,10 +58,10 @@
/**
* Makes a three-element instance.
*
- * @param spec0 non-null; the first element
- * @param spec1 non-null; the second element
- * @param spec2 non-null; the third element
- * @return non-null; an appropriately-constructed 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
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
RegisterSpec spec2) {
@@ -75,11 +75,11 @@
/**
* Makes a four-element instance.
*
- * @param spec0 non-null; the first element
- * @param spec1 non-null; the second element
- * @param spec2 non-null; the third element
- * @param spec3 non-null; the fourth element
- * @return non-null; an appropriately-constructed 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
+ * @param spec3 {@code non-null;} the fourth element
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static RegisterSpecList make(RegisterSpec spec0, RegisterSpec spec1,
RegisterSpec spec2,
@@ -93,7 +93,7 @@
}
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -126,10 +126,10 @@
/**
* 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</code>.
+ * will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which element
- * @return non-null; the indicated element
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
*/
public RegisterSpec get(int n) {
return (RegisterSpec) get0(n);
@@ -180,8 +180,8 @@
/**
* Sets the element at the given index.
*
- * @param n >= 0, < size(); which element
- * @param spec non-null; the value to store
+ * @param n {@code >= 0, < size();} which element
+ * @param spec {@code non-null;} the value to store
*/
public void set(int n, RegisterSpec spec) {
set0(n, spec);
@@ -193,7 +193,7 @@
* to plus the widest width (largest category) of the type used in
* that register.
*
- * @return >= 0; the required registers size
+ * @return {@code >= 0;} the required registers size
*/
public int getRegistersSize() {
int sz = size();
@@ -217,8 +217,8 @@
* except that it has an additional element prepended to the original.
* Mutability of the result is inherited from the original.
*
- * @param spec non-null; the new first spec (to prepend)
- * @return non-null; an appropriately-constructed instance
+ * @param spec {@code non-null;} the new first spec (to prepend)
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withFirst(RegisterSpec spec) {
int sz = size();
@@ -241,7 +241,7 @@
* except that its first element is removed. Mutability of the
* result is inherited from the original.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withoutFirst() {
int newSize = size() - 1;
@@ -268,7 +268,7 @@
* except that its last element is removed. Mutability of the
* result is inherited from the original.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withoutLast() {
int newSize = size() - 1;
@@ -296,7 +296,7 @@
* of the result is inherited from the original.
*
* @param delta the amount to offset the register numbers by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withOffset(int delta) {
int sz = size();
@@ -329,7 +329,7 @@
*
* @param base the base register number
* @param duplicateFirst whether to duplicate the first number
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecList withSequentialRegisters(int base,
boolean duplicateFirst) {
diff --git a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
index adc77c3..68009d9 100644
--- a/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
+++ b/dx/src/com/android/dx/rop/code/RegisterSpecSet.java
@@ -25,23 +25,23 @@
*/
public final class RegisterSpecSet
extends MutabilityControl {
- /** non-null; no-element instance */
+ /** {@code non-null;} no-element instance */
public static final RegisterSpecSet EMPTY = new RegisterSpecSet(0);
/**
- * non-null; array of register specs, where each element is
- * <code>null</code> or is an instance whose <code>reg</code>
+ * {@code non-null;} array of register specs, where each element is
+ * {@code null} or is an instance whose {@code reg}
* matches the array index
*/
private final RegisterSpec[] specs;
- /** >= -1; size of the set or <code>-1</code> if not yet calculated */
+ /** {@code >= -1;} size of the set or {@code -1} if not yet calculated */
private int size;
/**
* Constructs an instance. The instance is initially empty.
*
- * @param maxSize >= 0; the maximum register number (exclusive) that
+ * @param maxSize {@code >= 0;} the maximum register number (exclusive) that
* may be represented in this instance
*/
public RegisterSpecSet(int maxSize) {
@@ -127,7 +127,7 @@
* is also the maximum-plus-one of register numbers that may be
* represented.
*
- * @return >= 0; the maximum size
+ * @return {@code >= 0;} the maximum size
*/
public int getMaxSize() {
return specs.length;
@@ -136,7 +136,7 @@
/**
* Gets the current size of this instance.
*
- * @return >= 0; the size
+ * @return {@code >= 0;} the size
*/
public int size() {
int result = size;
@@ -160,9 +160,9 @@
/**
* Gets the element with the given register number, if any.
*
- * @param reg >= 0; the desired register number
- * @return null-ok; the element with the given register number or
- * <code>null</code> if there is none
+ * @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
*/
public RegisterSpec get(int reg) {
try {
@@ -176,11 +176,11 @@
/**
* 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())</code>.
+ * {@code get(spec.getReg())}.
*
- * @param spec non-null; spec with the desired register number
- * @return null-ok; the element with the matching register number or
- * <code>null</code> if there is none
+ * @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
*/
public RegisterSpec get(RegisterSpec spec) {
return get(spec.getReg());
@@ -192,8 +192,8 @@
* none. This ignores the register number of the given spec but
* matches on everything else.
*
- * @param spec non-null; local to look for
- * @return null-ok; first register found that matches, if any
+ * @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;
@@ -217,8 +217,8 @@
* Returns the spec in this set that's currently associated with a given
* local (name and signature), or {@code null} if there is none.
*
- * @param local non-null; local item to search for
- * @return null-ok; first register found with matching name and signature
+ * @param local {@code non-null;} local item to search for
+ * @return {@code null-ok;} first register found with matching name and signature
*/
public RegisterSpec localItemToSpec(LocalItem local) {
int length = specs.length;
@@ -238,7 +238,7 @@
* Removes a spec from the set. Only the register number
* of the parameter is significant.
*
- * @param toRemove non-null; register to remove.
+ * @param toRemove {@code non-null;} register to remove.
*/
public void remove(RegisterSpec toRemove) {
try {
@@ -258,7 +258,7 @@
* a category-2 register, then the immediately subsequent element
* is nullified.
*
- * @param spec non-null; the register spec to put in the instance
+ * @param spec {@code non-null;} the register spec to put in the instance
*/
public void put(RegisterSpec spec) {
throwIfImmutable();
@@ -293,7 +293,7 @@
/**
* Put the entire contents of the given set into this one.
*
- * @param set non-null; the set to put into this instance
+ * @param set {@code non-null;} the set to put into this instance
*/
public void putAll(RegisterSpecSet set) {
int max = set.getMaxSize();
@@ -312,11 +312,11 @@
* {@link RegisterSpec#intersect} of corresponding elements from
* this instance and the given one where both are non-null.
*
- * @param other non-null; set to intersect with
+ * @param other {@code non-null;} set to intersect with
* @param localPrimary whether local variables are primary to
- * the intersection; if <code>true</code>, then the only non-null
+ * the intersection; if {@code true}, then the only non-null
* result elements occur when registers being intersected have
- * equal names (or both have <code>null</code> names)
+ * equal names (or both have {@code null} names)
*/
public void intersect(RegisterSpecSet other, boolean localPrimary) {
throwIfImmutable();
@@ -352,7 +352,7 @@
* of the result is inherited from the original.
*
* @param delta the amount to offset the register numbers by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RegisterSpecSet withOffset(int delta) {
int len = specs.length;
@@ -377,7 +377,7 @@
/**
* Makes and return a mutable copy of this instance.
*
- * @return non-null; the mutable copy
+ * @return {@code non-null;} the mutable copy
*/
public RegisterSpecSet mutableCopy() {
int len = specs.length;
diff --git a/dx/src/com/android/dx/rop/code/Rop.java b/dx/src/com/android/dx/rop/code/Rop.java
index f918e12..fbd9a16 100644
--- a/dx/src/com/android/dx/rop/code/Rop.java
+++ b/dx/src/com/android/dx/rop/code/Rop.java
@@ -25,7 +25,7 @@
* Class that describes all the immutable parts of register-based operations.
*/
public final class Rop {
- /** minimum <code>BRANCH_*</code> value */
+ /** minimum {@code BRANCH_*} value */
public static final int BRANCH_MIN = 1;
/** indicates a non-branching op */
@@ -46,26 +46,26 @@
/** indicates a throw-style branch (both always-throws and may-throw) */
public static final int BRANCH_THROW = 6;
- /** maximum <code>BRANCH_*</code> value */
+ /** maximum {@code BRANCH_*} value */
public static final int BRANCH_MAX = 6;
/** the opcode; one of the constants in {@link RegOps} */
private final int opcode;
/**
- * non-null; result type of this operation; {@link Type#VOID} for
+ * {@code non-null;} result type of this operation; {@link Type#VOID} for
* no-result operations
*/
private final Type result;
- /** non-null; types of all the sources of this operation */
+ /** {@code non-null;} types of all the sources of this operation */
private final TypeList sources;
- /** non-null; list of possible types thrown by this operation */
+ /** {@code non-null;} list of possible types thrown by this operation */
private final TypeList exceptions;
/**
- * the branchingness of this op; one of the <code>BRANCH_*</code>
+ * the branchingness of this op; one of the {@code BRANCH_*}
* constants in this class
*/
private final int branchingness;
@@ -73,7 +73,7 @@
/** whether this is a function/method call op or similar */
private final boolean isCallLike;
- /** null-ok; nickname, if specified (used for debugging) */
+ /** {@code null-ok;} nickname, if specified (used for debugging) */
private final String nickname;
/**
@@ -81,15 +81,15 @@
* public constructors.
*
* @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result non-null; result type of this operation; {@link
+ * @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
- * @param sources non-null; types of all the sources of this operation
- * @param exceptions non-null; list of possible types thrown by this
+ * @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
* operation
* @param branchingness the branchingness of this op; one of the
- * <code>BRANCH_*</code> constants
+ * {@code BRANCH_*} constants
* @param isCallLike whether the op is a function/method call or similar
- * @param nickname null-ok; optional nickname (used for debugging)
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources,
TypeList exceptions, int branchingness, boolean isCallLike,
@@ -129,14 +129,14 @@
* call-like op (see {@link #isCallLike}).
*
* @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result non-null; result type of this operation; {@link
+ * @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
- * @param sources non-null; types of all the sources of this operation
- * @param exceptions non-null; list of possible types thrown by this
+ * @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
* operation
* @param branchingness the branchingness of this op; one of the
- * <code>BRANCH_*</code> constants
- * @param nickname null-ok; optional nickname (used for debugging)
+ * {@code BRANCH_*} constants
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources,
TypeList exceptions, int branchingness, String nickname) {
@@ -149,12 +149,12 @@
* call-like op (see {@link #isCallLike}).
*
* @param opcode the opcode; one of the constants in {@link RegOps}
- * @param result non-null; result type of this operation; {@link
+ * @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
- * @param sources non-null; types of all the sources of this operation
+ * @param sources {@code non-null;} types of all the sources of this operation
* @param branchingness the branchingness of this op; one of the
- * <code>BRANCH_*</code> constants
- * @param nickname null-ok; optional nickname (used for debugging)
+ * {@code BRANCH_*} constants
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources, int branchingness,
String nickname) {
@@ -164,14 +164,14 @@
/**
* Constructs a non-branching no-exception instance. The
- * <code>branchingness</code> is always <code>BRANCH_NONE</code>,
+ * {@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 non-null; result type of this operation; {@link
+ * @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
- * @param sources non-null; types of all the sources of this operation
- * @param nickname null-ok; optional nickname (used for debugging)
+ * @param sources {@code non-null;} types of all the sources of this operation
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources, String nickname) {
this(opcode, result, sources, StdTypeList.EMPTY, Rop.BRANCH_NONE,
@@ -180,16 +180,16 @@
/**
* Constructs a non-empty exceptions instance. Its
- * <code>branchingness</code> is always <code>BRANCH_THROW</code>,
+ * {@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 non-null; result type of this operation; {@link
+ * @param result {@code non-null;} result type of this operation; {@link
* Type#VOID} for no-result operations
- * @param sources non-null; types of all the sources of this operation
- * @param exceptions non-null; list of possible types thrown by this
+ * @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
* operation
- * @param nickname null-ok; optional nickname (used for debugging)
+ * @param nickname {@code null-ok;} optional nickname (used for debugging)
*/
public Rop(int opcode, Type result, TypeList sources, TypeList exceptions,
String nickname) {
@@ -200,11 +200,11 @@
/**
* Constructs a non-nicknamed instance with non-empty exceptions, which
* is always a call-like op (see {@link #isCallLike}). Its
- * <code>branchingness</code> is always <code>BRANCH_THROW</code>.
+ * {@code branchingness} is always {@code BRANCH_THROW}.
*
* @param opcode the opcode; one of the constants in {@link RegOps}
- * @param sources non-null; types of all the sources of this operation
- * @param exceptions non-null; list of possible types thrown by this
+ * @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
* operation
*/
public Rop(int opcode, TypeList sources, TypeList exceptions) {
@@ -317,7 +317,7 @@
* Gets the result type. A return value of {@link Type#VOID}
* means this operation returns nothing.
*
- * @return null-ok; the result spec
+ * @return {@code null-ok;} the result spec
*/
public Type getResult() {
return result;
@@ -326,7 +326,7 @@
/**
* Gets the source types.
*
- * @return non-null; the source types
+ * @return {@code non-null;} the source types
*/
public TypeList getSources() {
return sources;
@@ -335,7 +335,7 @@
/**
* Gets the list of exception types that might be thrown.
*
- * @return non-null; the list of exception types
+ * @return {@code non-null;} the list of exception types
*/
public TypeList getExceptions() {
return exceptions;
@@ -353,7 +353,7 @@
/**
* Gets whether this opcode is a function/method call or similar.
*
- * @return <code>true</code> iff this opcode is call-like
+ * @return {@code true} iff this opcode is call-like
*/
public boolean isCallLike() {
return isCallLike;
@@ -384,7 +384,7 @@
* Gets the nickname. If this instance has no nickname, this returns
* the result of calling {@link #toString}.
*
- * @return non-null; the nickname
+ * @return {@code non-null;} the nickname
*/
public String getNickname() {
if (nickname != null) {
@@ -397,9 +397,9 @@
/**
* Gets whether this operation can possibly throw an exception. This
* is just a convenient wrapper for
- * <code>getExceptions().size() != 0</code>.
+ * {@code getExceptions().size() != 0}.
*
- * @return <code>true</code> iff this operation can possibly throw
+ * @return {@code true} iff this operation can possibly throw
*/
public final boolean canThrow() {
return (exceptions.size() != 0);
diff --git a/dx/src/com/android/dx/rop/code/RopMethod.java b/dx/src/com/android/dx/rop/code/RopMethod.java
index 0c0d8f1..3957532 100644
--- a/dx/src/com/android/dx/rop/code/RopMethod.java
+++ b/dx/src/com/android/dx/rop/code/RopMethod.java
@@ -24,20 +24,20 @@
* All of the parts that make up a method at the rop layer.
*/
public final class RopMethod {
- /** non-null; basic block list of the method */
+ /** {@code non-null;} basic block list of the method */
private final BasicBlockList blocks;
- /** >= 0; label for the block which starts the method */
+ /** {@code >= 0;} label for the block which starts the method */
private final int firstLabel;
/**
- * null-ok; array of predecessors for each block, indexed by block
+ * {@code null-ok;} array of predecessors for each block, indexed by block
* label
*/
private IntList[] predecessors;
/**
- * null-ok; the predecessors for the implicit "exit" block, that is
+ * {@code null-ok;} the predecessors for the implicit "exit" block, that is
* the labels for the blocks that return, if calculated
*/
private IntList exitPredecessors;
@@ -45,8 +45,8 @@
/**
* Constructs an instance.
*
- * @param blocks non-null; basic block list of the method
- * @param firstLabel >= 0; the label of the first block to execute
+ * @param blocks {@code non-null;} basic block list of the method
+ * @param firstLabel {@code >= 0;} the label of the first block to execute
*/
public RopMethod(BasicBlockList blocks, int firstLabel) {
if (blocks == null) {
@@ -67,7 +67,7 @@
/**
* Gets the basic block list for this method.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public BasicBlockList getBlocks() {
return blocks;
@@ -77,7 +77,7 @@
* Gets the label for the first block in the method that this list
* represents.
*
- * @return >= 0; the first-block label
+ * @return {@code >= 0;} the first-block label
*/
public int getFirstLabel() {
return firstLabel;
@@ -87,8 +87,8 @@
* Gets the predecessors associated with the given block. This throws
* an exception if there is no block with the given label.
*
- * @param label >= 0; the label of the block in question
- * @return non-null; the predecessors of that block
+ * @param label {@code >= 0;} the label of the block in question
+ * @return {@code non-null;} the predecessors of that block
*/
public IntList labelToPredecessors(int label) {
if (exitPredecessors == null) {
@@ -107,7 +107,7 @@
/**
* Gets the exit predecessors for this instance.
*
- * @return non-null; the exit predecessors
+ * @return {@code non-null;} the exit predecessors
*/
public IntList getExitPredecessors() {
if (exitPredecessors == null) {
@@ -124,7 +124,7 @@
* amount.
*
* @param delta the amount to offset register numbers by
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public RopMethod withRegisterOffset(int delta) {
RopMethod result = new RopMethod(blocks.withRegisterOffset(delta),
diff --git a/dx/src/com/android/dx/rop/code/Rops.java b/dx/src/com/android/dx/rop/code/Rops.java
index b662656..15c2e17 100644
--- a/dx/src/com/android/dx/rop/code/Rops.java
+++ b/dx/src/com/android/dx/rop/code/Rops.java
@@ -30,32 +30,32 @@
* Standard instances of {@link Rop}.
*/
public final class Rops {
- /** <code>nop()</code> */
+ /** {@code nop()} */
public static final Rop NOP =
new Rop(RegOps.NOP, Type.VOID, StdTypeList.EMPTY, "nop");
- /** <code>r,x: int :: r = x;</code> */
+ /** {@code r,x: int :: r = x;} */
public static final Rop MOVE_INT =
new Rop(RegOps.MOVE, Type.INT, StdTypeList.INT, "move-int");
- /** <code>r,x: long :: r = x;</code> */
+ /** {@code r,x: long :: r = x;} */
public static final Rop MOVE_LONG =
new Rop(RegOps.MOVE, Type.LONG, StdTypeList.LONG, "move-long");
- /** <code>r,x: float :: r = x;</code> */
+ /** {@code r,x: float :: r = x;} */
public static final Rop MOVE_FLOAT =
new Rop(RegOps.MOVE, Type.FLOAT, StdTypeList.FLOAT, "move-float");
- /** <code>r,x: double :: r = x;</code> */
+ /** {@code r,x: double :: r = x;} */
public static final Rop MOVE_DOUBLE =
new Rop(RegOps.MOVE, Type.DOUBLE, StdTypeList.DOUBLE, "move-double");
- /** <code>r,x: Object :: r = x;</code> */
+ /** {@code r,x: Object :: r = x;} */
public static final Rop MOVE_OBJECT =
new Rop(RegOps.MOVE, Type.OBJECT, StdTypeList.OBJECT, "move-object");
/**
- * <code>r,x: ReturnAddress :: r = x;</code>
+ * {@code r,x: ReturnAddress :: r = x;}
*
* Note that this rop-form instruction has no dex-form equivilent and
* must be removed before the dex conversion.
@@ -64,756 +64,756 @@
new Rop(RegOps.MOVE, Type.RETURN_ADDRESS,
StdTypeList.RETURN_ADDRESS, "move-return-address");
- /** <code>r,param(x): int :: r = param(x);</code> */
+ /** {@code r,param(x): int :: r = param(x);} */
public static final Rop MOVE_PARAM_INT =
new Rop(RegOps.MOVE_PARAM, Type.INT, StdTypeList.EMPTY,
"move-param-int");
- /** <code>r,param(x): long :: r = param(x);</code> */
+ /** {@code r,param(x): long :: r = param(x);} */
public static final Rop MOVE_PARAM_LONG =
new Rop(RegOps.MOVE_PARAM, Type.LONG, StdTypeList.EMPTY,
"move-param-long");
- /** <code>r,param(x): float :: r = param(x);</code> */
+ /** {@code r,param(x): float :: r = param(x);} */
public static final Rop MOVE_PARAM_FLOAT =
new Rop(RegOps.MOVE_PARAM, Type.FLOAT, StdTypeList.EMPTY,
"move-param-float");
- /** <code>r,param(x): double :: r = param(x);</code> */
+ /** {@code r,param(x): double :: r = param(x);} */
public static final Rop MOVE_PARAM_DOUBLE =
new Rop(RegOps.MOVE_PARAM, Type.DOUBLE, StdTypeList.EMPTY,
"move-param-double");
- /** <code>r,param(x): Object :: r = param(x);</code> */
+ /** {@code r,param(x): Object :: r = param(x);} */
public static final Rop MOVE_PARAM_OBJECT =
new Rop(RegOps.MOVE_PARAM, Type.OBJECT, StdTypeList.EMPTY,
"move-param-object");
- /** <code>r, literal: int :: r = literal;</code> */
+ /** {@code r, literal: int :: r = literal;} */
public static final Rop CONST_INT =
new Rop(RegOps.CONST, Type.INT, StdTypeList.EMPTY, "const-int");
- /** <code>r, literal: long :: r = literal;</code> */
+ /** {@code r, literal: long :: r = literal;} */
public static final Rop CONST_LONG =
new Rop(RegOps.CONST, Type.LONG, StdTypeList.EMPTY, "const-long");
- /** <code>r, literal: float :: r = literal;</code> */
+ /** {@code r, literal: float :: r = literal;} */
public static final Rop CONST_FLOAT =
new Rop(RegOps.CONST, Type.FLOAT, StdTypeList.EMPTY, "const-float");
- /** <code>r, literal: double :: r = literal;</code> */
+ /** {@code r, literal: double :: r = literal;} */
public static final Rop CONST_DOUBLE =
new Rop(RegOps.CONST, Type.DOUBLE, StdTypeList.EMPTY, "const-double");
- /** <code>r, literal: Object :: r = literal;</code> */
+ /** {@code r, literal: Object :: r = literal;} */
public static final Rop CONST_OBJECT =
new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "const-object");
- /** <code>r, literal: Object :: r = literal;</code> */
+ /** {@code r, literal: Object :: r = literal;} */
public static final Rop CONST_OBJECT_NOTHROW =
new Rop(RegOps.CONST, Type.OBJECT, StdTypeList.EMPTY,
"const-object-nothrow");
- /** <code>goto <i>label</i></code> */
+ /** {@code goto label} */
public static final Rop GOTO =
new Rop(RegOps.GOTO, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_GOTO,
"goto");
- /** <code>x: int :: if (x == 0) goto <i>label</i></code> */
+ /** {@code x: int :: if (x == 0) goto label} */
public static final Rop IF_EQZ_INT =
new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
"if-eqz-int");
- /** <code>x: int :: if (x != 0) goto <i>label</i></code> */
+ /** {@code x: int :: if (x != 0) goto label} */
public static final Rop IF_NEZ_INT =
new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
"if-nez-int");
- /** <code>x: int :: if (x < 0) goto <i>label</i></code> */
+ /** {@code x: int :: if (x < 0) goto label} */
public static final Rop IF_LTZ_INT =
new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
"if-ltz-int");
- /** <code>x: int :: if (x >= 0) goto <i>label</i></code> */
+ /** {@code x: int :: if (x >= 0) goto label} */
public static final Rop IF_GEZ_INT =
new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
"if-gez-int");
- /** <code>x: int :: if (x <= 0) goto <i>label</i></code> */
+ /** {@code x: int :: if (x <= 0) goto label} */
public static final Rop IF_LEZ_INT =
new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
"if-lez-int");
- /** <code>x: int :: if (x > 0) goto <i>label</i></code> */
+ /** {@code x: int :: if (x > 0) goto label} */
public static final Rop IF_GTZ_INT =
new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT, Rop.BRANCH_IF,
"if-gtz-int");
- /** <code>x: Object :: if (x == null) goto <i>label</i></code> */
+ /** {@code x: Object :: if (x == null) goto label} */
public static final Rop IF_EQZ_OBJECT =
new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF,
"if-eqz-object");
- /** <code>x: Object :: if (x != null) goto <i>label</i></code> */
+ /** {@code x: Object :: if (x != null) goto label} */
public static final Rop IF_NEZ_OBJECT =
new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT, Rop.BRANCH_IF,
"if-nez-object");
- /** <code>x,y: int :: if (x == y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x == y) goto label} */
public static final Rop IF_EQ_INT =
new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
"if-eq-int");
- /** <code>x,y: int :: if (x != y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x != y) goto label} */
public static final Rop IF_NE_INT =
new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
"if-ne-int");
- /** <code>x,y: int :: if (x < y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x < y) goto label} */
public static final Rop IF_LT_INT =
new Rop(RegOps.IF_LT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
"if-lt-int");
- /** <code>x,y: int :: if (x >= y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x >= y) goto label} */
public static final Rop IF_GE_INT =
new Rop(RegOps.IF_GE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
"if-ge-int");
- /** <code>x,y: int :: if (x <= y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x <= y) goto label} */
public static final Rop IF_LE_INT =
new Rop(RegOps.IF_LE, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
"if-le-int");
- /** <code>x,y: int :: if (x > y) goto <i>label</i></code> */
+ /** {@code x,y: int :: if (x > y) goto label} */
public static final Rop IF_GT_INT =
new Rop(RegOps.IF_GT, Type.VOID, StdTypeList.INT_INT, Rop.BRANCH_IF,
"if-gt-int");
- /** <code>x,y: Object :: if (x == y) goto <i>label</i></code> */
+ /** {@code x,y: Object :: if (x == y) goto label} */
public static final Rop IF_EQ_OBJECT =
new Rop(RegOps.IF_EQ, Type.VOID, StdTypeList.OBJECT_OBJECT,
Rop.BRANCH_IF, "if-eq-object");
- /** <code>x,y: Object :: if (x != y) goto <i>label</i></code> */
+ /** {@code x,y: Object :: if (x != y) goto label} */
public static final Rop IF_NE_OBJECT =
new Rop(RegOps.IF_NE, Type.VOID, StdTypeList.OBJECT_OBJECT,
Rop.BRANCH_IF, "if-ne-object");
- /** <code>x: int :: goto switchtable[x]</code> */
+ /** {@code x: int :: goto switchtable[x]} */
public static final Rop SWITCH =
new Rop(RegOps.SWITCH, Type.VOID, StdTypeList.INT, Rop.BRANCH_SWITCH,
"switch");
- /** <code>r,x,y: int :: r = x + y;</code> */
+ /** {@code r,x,y: int :: r = x + y;} */
public static final Rop ADD_INT =
new Rop(RegOps.ADD, Type.INT, StdTypeList.INT_INT, "add-int");
- /** <code>r,x,y: long :: r = x + y;</code> */
+ /** {@code r,x,y: long :: r = x + y;} */
public static final Rop ADD_LONG =
new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG_LONG, "add-long");
- /** <code>r,x,y: float :: r = x + y;</code> */
+ /** {@code r,x,y: float :: r = x + y;} */
public static final Rop ADD_FLOAT =
new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "add-float");
- /** <code>r,x,y: double :: r = x + y;</code> */
+ /** {@code r,x,y: double :: r = x + y;} */
public static final Rop ADD_DOUBLE =
new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
Rop.BRANCH_NONE, "add-double");
- /** <code>r,x,y: int :: r = x - y;</code> */
+ /** {@code r,x,y: int :: r = x - y;} */
public static final Rop SUB_INT =
new Rop(RegOps.SUB, Type.INT, StdTypeList.INT_INT, "sub-int");
- /** <code>r,x,y: long :: r = x - y;</code> */
+ /** {@code r,x,y: long :: r = x - y;} */
public static final Rop SUB_LONG =
new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG_LONG, "sub-long");
- /** <code>r,x,y: float :: r = x - y;</code> */
+ /** {@code r,x,y: float :: r = x - y;} */
public static final Rop SUB_FLOAT =
new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "sub-float");
- /** <code>r,x,y: double :: r = x - y;</code> */
+ /** {@code r,x,y: double :: r = x - y;} */
public static final Rop SUB_DOUBLE =
new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
Rop.BRANCH_NONE, "sub-double");
- /** <code>r,x,y: int :: r = x * y;</code> */
+ /** {@code r,x,y: int :: r = x * y;} */
public static final Rop MUL_INT =
new Rop(RegOps.MUL, Type.INT, StdTypeList.INT_INT, "mul-int");
- /** <code>r,x,y: long :: r = x * y;</code> */
+ /** {@code r,x,y: long :: r = x * y;} */
public static final Rop MUL_LONG =
new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG_LONG, "mul-long");
- /** <code>r,x,y: float :: r = x * y;</code> */
+ /** {@code r,x,y: float :: r = x * y;} */
public static final Rop MUL_FLOAT =
new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "mul-float");
- /** <code>r,x,y: double :: r = x * y;</code> */
+ /** {@code r,x,y: double :: r = x * y;} */
public static final Rop MUL_DOUBLE =
new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
Rop.BRANCH_NONE, "mul-double");
- /** <code>r,x,y: int :: r = x / y;</code> */
+ /** {@code r,x,y: int :: r = x / y;} */
public static final Rop DIV_INT =
new Rop(RegOps.DIV, Type.INT, StdTypeList.INT_INT,
Exceptions.LIST_Error_ArithmeticException, "div-int");
- /** <code>r,x,y: long :: r = x / y;</code> */
+ /** {@code r,x,y: long :: r = x / y;} */
public static final Rop DIV_LONG =
new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG_LONG,
Exceptions.LIST_Error_ArithmeticException, "div-long");
- /** <code>r,x,y: float :: r = x / y;</code> */
+ /** {@code r,x,y: float :: r = x / y;} */
public static final Rop DIV_FLOAT =
new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "div-float");
- /** <code>r,x,y: double :: r = x / y;</code> */
+ /** {@code r,x,y: double :: r = x / y;} */
public static final Rop DIV_DOUBLE =
new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
"div-double");
- /** <code>r,x,y: int :: r = x % y;</code> */
+ /** {@code r,x,y: int :: r = x % y;} */
public static final Rop REM_INT =
new Rop(RegOps.REM, Type.INT, StdTypeList.INT_INT,
Exceptions.LIST_Error_ArithmeticException, "rem-int");
- /** <code>r,x,y: long :: r = x % y;</code> */
+ /** {@code r,x,y: long :: r = x % y;} */
public static final Rop REM_LONG =
new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG_LONG,
Exceptions.LIST_Error_ArithmeticException, "rem-long");
- /** <code>r,x,y: float :: r = x % y;</code> */
+ /** {@code r,x,y: float :: r = x % y;} */
public static final Rop REM_FLOAT =
new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT_FLOAT, "rem-float");
- /** <code>r,x,y: double :: r = x % y;</code> */
+ /** {@code r,x,y: double :: r = x % y;} */
public static final Rop REM_DOUBLE =
new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE_DOUBLE,
"rem-double");
- /** <code>r,x: int :: r = -x;</code> */
+ /** {@code r,x: int :: r = -x;} */
public static final Rop NEG_INT =
new Rop(RegOps.NEG, Type.INT, StdTypeList.INT, "neg-int");
- /** <code>r,x: long :: r = -x;</code> */
+ /** {@code r,x: long :: r = -x;} */
public static final Rop NEG_LONG =
new Rop(RegOps.NEG, Type.LONG, StdTypeList.LONG, "neg-long");
- /** <code>r,x: float :: r = -x;</code> */
+ /** {@code r,x: float :: r = -x;} */
public static final Rop NEG_FLOAT =
new Rop(RegOps.NEG, Type.FLOAT, StdTypeList.FLOAT, "neg-float");
- /** <code>r,x: double :: r = -x;</code> */
+ /** {@code r,x: double :: r = -x;} */
public static final Rop NEG_DOUBLE =
new Rop(RegOps.NEG, Type.DOUBLE, StdTypeList.DOUBLE, "neg-double");
- /** <code>r,x,y: int :: r = x & y;</code> */
+ /** {@code r,x,y: int :: r = x & y;} */
public static final Rop AND_INT =
new Rop(RegOps.AND, Type.INT, StdTypeList.INT_INT, "and-int");
- /** <code>r,x,y: long :: r = x & y;</code> */
+ /** {@code r,x,y: long :: r = x & y;} */
public static final Rop AND_LONG =
new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG_LONG, "and-long");
- /** <code>r,x,y: int :: r = x | y;</code> */
+ /** {@code r,x,y: int :: r = x | y;} */
public static final Rop OR_INT =
new Rop(RegOps.OR, Type.INT, StdTypeList.INT_INT, "or-int");
- /** <code>r,x,y: long :: r = x | y;</code> */
+ /** {@code r,x,y: long :: r = x | y;} */
public static final Rop OR_LONG =
new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG_LONG, "or-long");
- /** <code>r,x,y: int :: r = x ^ y;</code> */
+ /** {@code r,x,y: int :: r = x ^ y;} */
public static final Rop XOR_INT =
new Rop(RegOps.XOR, Type.INT, StdTypeList.INT_INT, "xor-int");
- /** <code>r,x,y: long :: r = x ^ y;</code> */
+ /** {@code r,x,y: long :: r = x ^ y;} */
public static final Rop XOR_LONG =
new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG_LONG, "xor-long");
- /** <code>r,x,y: int :: r = x << y;</code> */
+ /** {@code r,x,y: int :: r = x << y;} */
public static final Rop SHL_INT =
new Rop(RegOps.SHL, Type.INT, StdTypeList.INT_INT, "shl-int");
- /** <code>r,x: long; y: int :: r = x << y;</code> */
+ /** {@code r,x: long; y: int :: r = x << y;} */
public static final Rop SHL_LONG =
new Rop(RegOps.SHL, Type.LONG, StdTypeList.LONG_INT, "shl-long");
- /** <code>r,x,y: int :: r = x >> y;</code> */
+ /** {@code r,x,y: int :: r = x >> y;} */
public static final Rop SHR_INT =
new Rop(RegOps.SHR, Type.INT, StdTypeList.INT_INT, "shr-int");
- /** <code>r,x: long; y: int :: r = x >> y;</code> */
+ /** {@code r,x: long; y: int :: r = x >> y;} */
public static final Rop SHR_LONG =
new Rop(RegOps.SHR, Type.LONG, StdTypeList.LONG_INT, "shr-long");
- /** <code>r,x,y: int :: r = x >>> y;</code> */
+ /** {@code r,x,y: int :: r = x >>> y;} */
public static final Rop USHR_INT =
new Rop(RegOps.USHR, Type.INT, StdTypeList.INT_INT, "ushr-int");
- /** <code>r,x: long; y: int :: r = x >>> y;</code> */
+ /** {@code r,x: long; y: int :: r = x >>> y;} */
public static final Rop USHR_LONG =
new Rop(RegOps.USHR, Type.LONG, StdTypeList.LONG_INT, "ushr-long");
- /** <code>r,x: int :: r = ~x;</code> */
+ /** {@code r,x: int :: r = ~x;} */
public static final Rop NOT_INT =
new Rop(RegOps.NOT, Type.INT, StdTypeList.INT, "not-int");
- /** <code>r,x: long :: r = ~x;</code> */
+ /** {@code r,x: long :: r = ~x;} */
public static final Rop NOT_LONG =
new Rop(RegOps.NOT, Type.LONG, StdTypeList.LONG, "not-long");
- /** <code>r,x,c: int :: r = x + c;</code> */
+ /** {@code r,x,c: int :: r = x + c;} */
public static final Rop ADD_CONST_INT =
new Rop(RegOps.ADD, Type.INT, StdTypeList.INT, "add-const-int");
- /** <code>r,x,c: long :: r = x + c;</code> */
+ /** {@code r,x,c: long :: r = x + c;} */
public static final Rop ADD_CONST_LONG =
new Rop(RegOps.ADD, Type.LONG, StdTypeList.LONG, "add-const-long");
- /** <code>r,x,c: float :: r = x + c;</code> */
+ /** {@code r,x,c: float :: r = x + c;} */
public static final Rop ADD_CONST_FLOAT =
new Rop(RegOps.ADD, Type.FLOAT, StdTypeList.FLOAT, "add-const-float");
- /** <code>r,x,c: double :: r = x + c;</code> */
+ /** {@code r,x,c: double :: r = x + c;} */
public static final Rop ADD_CONST_DOUBLE =
new Rop(RegOps.ADD, Type.DOUBLE, StdTypeList.DOUBLE,
"add-const-double");
- /** <code>r,x,c: int :: r = x - c;</code> */
+ /** {@code r,x,c: int :: r = x - c;} */
public static final Rop SUB_CONST_INT =
new Rop(RegOps.SUB, Type.INT, StdTypeList.INT, "sub-const-int");
- /** <code>r,x,c: long :: r = x - c;</code> */
+ /** {@code r,x,c: long :: r = x - c;} */
public static final Rop SUB_CONST_LONG =
new Rop(RegOps.SUB, Type.LONG, StdTypeList.LONG, "sub-const-long");
- /** <code>r,x,c: float :: r = x - c;</code> */
+ /** {@code r,x,c: float :: r = x - c;} */
public static final Rop SUB_CONST_FLOAT =
new Rop(RegOps.SUB, Type.FLOAT, StdTypeList.FLOAT, "sub-const-float");
- /** <code>r,x,c: double :: r = x - c;</code> */
+ /** {@code r,x,c: double :: r = x - c;} */
public static final Rop SUB_CONST_DOUBLE =
new Rop(RegOps.SUB, Type.DOUBLE, StdTypeList.DOUBLE,
"sub-const-double");
- /** <code>r,x,c: int :: r = x * c;</code> */
+ /** {@code r,x,c: int :: r = x * c;} */
public static final Rop MUL_CONST_INT =
new Rop(RegOps.MUL, Type.INT, StdTypeList.INT, "mul-const-int");
- /** <code>r,x,c: long :: r = x * c;</code> */
+ /** {@code r,x,c: long :: r = x * c;} */
public static final Rop MUL_CONST_LONG =
new Rop(RegOps.MUL, Type.LONG, StdTypeList.LONG, "mul-const-long");
- /** <code>r,x,c: float :: r = x * c;</code> */
+ /** {@code r,x,c: float :: r = x * c;} */
public static final Rop MUL_CONST_FLOAT =
new Rop(RegOps.MUL, Type.FLOAT, StdTypeList.FLOAT, "mul-const-float");
- /** <code>r,x,c: double :: r = x * c;</code> */
+ /** {@code r,x,c: double :: r = x * c;} */
public static final Rop MUL_CONST_DOUBLE =
new Rop(RegOps.MUL, Type.DOUBLE, StdTypeList.DOUBLE,
"mul-const-double");
- /** <code>r,x,c: int :: r = x / c;</code> */
+ /** {@code r,x,c: int :: r = x / c;} */
public static final Rop DIV_CONST_INT =
new Rop(RegOps.DIV, Type.INT, StdTypeList.INT,
Exceptions.LIST_Error_ArithmeticException, "div-const-int");
- /** <code>r,x,c: long :: r = x / c;</code> */
+ /** {@code r,x,c: long :: r = x / c;} */
public static final Rop DIV_CONST_LONG =
new Rop(RegOps.DIV, Type.LONG, StdTypeList.LONG,
Exceptions.LIST_Error_ArithmeticException, "div-const-long");
- /** <code>r,x,c: float :: r = x / c;</code> */
+ /** {@code r,x,c: float :: r = x / c;} */
public static final Rop DIV_CONST_FLOAT =
new Rop(RegOps.DIV, Type.FLOAT, StdTypeList.FLOAT, "div-const-float");
- /** <code>r,x,c: double :: r = x / c;</code> */
+ /** {@code r,x,c: double :: r = x / c;} */
public static final Rop DIV_CONST_DOUBLE =
new Rop(RegOps.DIV, Type.DOUBLE, StdTypeList.DOUBLE,
"div-const-double");
- /** <code>r,x,c: int :: r = x % c;</code> */
+ /** {@code r,x,c: int :: r = x % c;} */
public static final Rop REM_CONST_INT =
new Rop(RegOps.REM, Type.INT, StdTypeList.INT,
Exceptions.LIST_Error_ArithmeticException, "rem-const-int");
- /** <code>r,x,c: long :: r = x % c;</code> */
+ /** {@code r,x,c: long :: r = x % c;} */
public static final Rop REM_CONST_LONG =
new Rop(RegOps.REM, Type.LONG, StdTypeList.LONG,
Exceptions.LIST_Error_ArithmeticException, "rem-const-long");
- /** <code>r,x,c: float :: r = x % c;</code> */
+ /** {@code r,x,c: float :: r = x % c;} */
public static final Rop REM_CONST_FLOAT =
new Rop(RegOps.REM, Type.FLOAT, StdTypeList.FLOAT, "rem-const-float");
- /** <code>r,x,c: double :: r = x % c;</code> */
+ /** {@code r,x,c: double :: r = x % c;} */
public static final Rop REM_CONST_DOUBLE =
new Rop(RegOps.REM, Type.DOUBLE, StdTypeList.DOUBLE,
"rem-const-double");
- /** <code>r,x,c: int :: r = x & c;</code> */
+ /** {@code r,x,c: int :: r = x & c;} */
public static final Rop AND_CONST_INT =
new Rop(RegOps.AND, Type.INT, StdTypeList.INT, "and-const-int");
- /** <code>r,x,c: long :: r = x & c;</code> */
+ /** {@code r,x,c: long :: r = x & c;} */
public static final Rop AND_CONST_LONG =
new Rop(RegOps.AND, Type.LONG, StdTypeList.LONG, "and-const-long");
- /** <code>r,x,c: int :: r = x | c;</code> */
+ /** {@code r,x,c: int :: r = x | c;} */
public static final Rop OR_CONST_INT =
new Rop(RegOps.OR, Type.INT, StdTypeList.INT, "or-const-int");
- /** <code>r,x,c: long :: r = x | c;</code> */
+ /** {@code r,x,c: long :: r = x | c;} */
public static final Rop OR_CONST_LONG =
new Rop(RegOps.OR, Type.LONG, StdTypeList.LONG, "or-const-long");
- /** <code>r,x,c: int :: r = x ^ c;</code> */
+ /** {@code r,x,c: int :: r = x ^ c;} */
public static final Rop XOR_CONST_INT =
new Rop(RegOps.XOR, Type.INT, StdTypeList.INT, "xor-const-int");
- /** <code>r,x,c: long :: r = x ^ c;</code> */
+ /** {@code r,x,c: long :: r = x ^ c;} */
public static final Rop XOR_CONST_LONG =
new Rop(RegOps.XOR, Type.LONG, StdTypeList.LONG, "xor-const-long");
- /** <code>r,x,c: int :: r = x << c;</code> */
+ /** {@code r,x,c: int :: r = x << c;} */
public static final Rop SHL_CONST_INT =
new Rop(RegOps.SHL, Type.INT, StdTypeList.INT, "shl-const-int");
- /** <code>r,x: long; c: int :: r = x << c;</code> */
+ /** {@code r,x: long; c: int :: r = x << c;} */
public static final Rop SHL_CONST_LONG =
new Rop(RegOps.SHL, Type.LONG, StdTypeList.INT, "shl-const-long");
- /** <code>r,x,c: int :: r = x >> c;</code> */
+ /** {@code r,x,c: int :: r = x >> c;} */
public static final Rop SHR_CONST_INT =
new Rop(RegOps.SHR, Type.INT, StdTypeList.INT, "shr-const-int");
- /** <code>r,x: long; c: int :: r = x >> c;</code> */
+ /** {@code r,x: long; c: int :: r = x >> c;} */
public static final Rop SHR_CONST_LONG =
new Rop(RegOps.SHR, Type.LONG, StdTypeList.INT, "shr-const-long");
- /** <code>r,x,c: int :: r = x >>> c;</code> */
+ /** {@code r,x,c: int :: r = x >>> c;} */
public static final Rop USHR_CONST_INT =
new Rop(RegOps.USHR, Type.INT, StdTypeList.INT, "ushr-const-int");
- /** <code>r,x: long; c: int :: r = x >>> c;</code> */
+ /** {@code r,x: long; c: int :: r = x >>> c;} */
public static final Rop USHR_CONST_LONG =
new Rop(RegOps.USHR, Type.LONG, StdTypeList.INT, "ushr-const-long");
- /** <code>r: int; x,y: long :: r = cmp(x, y);</code> */
+ /** {@code r: int; x,y: long :: r = cmp(x, y);} */
public static final Rop CMPL_LONG =
new Rop(RegOps.CMPL, Type.INT, StdTypeList.LONG_LONG, "cmpl-long");
- /** <code>r: int; x,y: float :: r = cmpl(x, y);</code> */
+ /** {@code r: int; x,y: float :: r = cmpl(x, y);} */
public static final Rop CMPL_FLOAT =
new Rop(RegOps.CMPL, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpl-float");
- /** <code>r: int; x,y: double :: r = cmpl(x, y);</code> */
+ /** {@code r: int; x,y: double :: r = cmpl(x, y);} */
public static final Rop CMPL_DOUBLE =
new Rop(RegOps.CMPL, Type.INT, StdTypeList.DOUBLE_DOUBLE,
"cmpl-double");
- /** <code>r: int; x,y: float :: r = cmpg(x, y);</code> */
+ /** {@code r: int; x,y: float :: r = cmpg(x, y);} */
public static final Rop CMPG_FLOAT =
new Rop(RegOps.CMPG, Type.INT, StdTypeList.FLOAT_FLOAT, "cmpg-float");
- /** <code>r: int; x,y: double :: r = cmpg(x, y);</code> */
+ /** {@code r: int; x,y: double :: r = cmpg(x, y);} */
public static final Rop CMPG_DOUBLE =
new Rop(RegOps.CMPG, Type.INT, StdTypeList.DOUBLE_DOUBLE,
"cmpg-double");
- /** <code>r: int; x: long :: r = (int) x</code> */
+ /** {@code r: int; x: long :: r = (int) x} */
public static final Rop CONV_L2I =
new Rop(RegOps.CONV, Type.INT, StdTypeList.LONG, "conv-l2i");
- /** <code>r: int; x: float :: r = (int) x</code> */
+ /** {@code r: int; x: float :: r = (int) x} */
public static final Rop CONV_F2I =
new Rop(RegOps.CONV, Type.INT, StdTypeList.FLOAT, "conv-f2i");
- /** <code>r: int; x: double :: r = (int) x</code> */
+ /** {@code r: int; x: double :: r = (int) x} */
public static final Rop CONV_D2I =
new Rop(RegOps.CONV, Type.INT, StdTypeList.DOUBLE, "conv-d2i");
- /** <code>r: long; x: int :: r = (long) x</code> */
+ /** {@code r: long; x: int :: r = (long) x} */
public static final Rop CONV_I2L =
new Rop(RegOps.CONV, Type.LONG, StdTypeList.INT, "conv-i2l");
- /** <code>r: long; x: float :: r = (long) x</code> */
+ /** {@code r: long; x: float :: r = (long) x} */
public static final Rop CONV_F2L =
new Rop(RegOps.CONV, Type.LONG, StdTypeList.FLOAT, "conv-f2l");
- /** <code>r: long; x: double :: r = (long) x</code> */
+ /** {@code r: long; x: double :: r = (long) x} */
public static final Rop CONV_D2L =
new Rop(RegOps.CONV, Type.LONG, StdTypeList.DOUBLE, "conv-d2l");
- /** <code>r: float; x: int :: r = (float) x</code> */
+ /** {@code r: float; x: int :: r = (float) x} */
public static final Rop CONV_I2F =
new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.INT, "conv-i2f");
- /** <code>r: float; x: long :: r = (float) x</code> */
+ /** {@code r: float; x: long :: r = (float) x} */
public static final Rop CONV_L2F =
new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.LONG, "conv-l2f");
- /** <code>r: float; x: double :: r = (float) x</code> */
+ /** {@code r: float; x: double :: r = (float) x} */
public static final Rop CONV_D2F =
new Rop(RegOps.CONV, Type.FLOAT, StdTypeList.DOUBLE, "conv-d2f");
- /** <code>r: double; x: int :: r = (double) x</code> */
+ /** {@code r: double; x: int :: r = (double) x} */
public static final Rop CONV_I2D =
new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.INT, "conv-i2d");
- /** <code>r: double; x: long :: r = (double) x</code> */
+ /** {@code r: double; x: long :: r = (double) x} */
public static final Rop CONV_L2D =
new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.LONG, "conv-l2d");
- /** <code>r: double; x: float :: r = (double) x</code> */
+ /** {@code r: double; x: float :: r = (double) x} */
public static final Rop CONV_F2D =
new Rop(RegOps.CONV, Type.DOUBLE, StdTypeList.FLOAT, "conv-f2d");
/**
- * <code>r,x: int :: r = (x << 24) >> 24</code> (Java-style
+ * {@code r,x: int :: r = (x << 24) >> 24} (Java-style
* convert int 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</code> (Java-style
+ * {@code r,x: int :: r = x & 0xffff} (Java-style
* 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</code> (Java-style
+ * {@code r,x: int :: r = (x << 16) >> 16} (Java-style
* convert int to short)
*/
public static final Rop TO_SHORT =
new Rop(RegOps.TO_SHORT, Type.INT, StdTypeList.INT, "to-short");
- /** <code>return void</code> */
+ /** {@code return void} */
public static final Rop RETURN_VOID =
new Rop(RegOps.RETURN, Type.VOID, StdTypeList.EMPTY, Rop.BRANCH_RETURN,
"return-void");
- /** <code>x: int; return x</code> */
+ /** {@code x: int; return x} */
public static final Rop RETURN_INT =
new Rop(RegOps.RETURN, Type.VOID, StdTypeList.INT, Rop.BRANCH_RETURN,
"return-int");
- /** <code>x: long; return x</code> */
+ /** {@code x: long; return x} */
public static final Rop RETURN_LONG =
new Rop(RegOps.RETURN, Type.VOID, StdTypeList.LONG, Rop.BRANCH_RETURN,
"return-long");
- /** <code>x: float; return x</code> */
+ /** {@code x: float; return x} */
public static final Rop RETURN_FLOAT =
new Rop(RegOps.RETURN, Type.VOID, StdTypeList.FLOAT, Rop.BRANCH_RETURN,
"return-float");
- /** <code>x: double; return x</code> */
+ /** {@code x: double; return x} */
public static final Rop RETURN_DOUBLE =
new Rop(RegOps.RETURN, Type.VOID, StdTypeList.DOUBLE,
Rop.BRANCH_RETURN, "return-double");
- /** <code>x: Object; return x</code> */
+ /** {@code x: Object; return x} */
public static final Rop RETURN_OBJECT =
new Rop(RegOps.RETURN, Type.VOID, StdTypeList.OBJECT,
Rop.BRANCH_RETURN, "return-object");
- /** <code>T: any type; r: int; x: T[]; :: r = x.length</code> */
+ /** {@code T: any type; r: int; x: T[]; :: r = x.length} */
public static final Rop ARRAY_LENGTH =
new Rop(RegOps.ARRAY_LENGTH, Type.INT, StdTypeList.OBJECT,
Exceptions.LIST_Error_NullPointerException, "array-length");
- /** <code>x: Throwable :: throw(x)</code> */
+ /** {@code x: Throwable :: throw(x)} */
public static final Rop THROW =
new Rop(RegOps.THROW, Type.VOID, StdTypeList.THROWABLE,
StdTypeList.THROWABLE, "throw");
- /** <code>x: Object :: monitorenter(x)</code> */
+ /** {@code x: Object :: monitorenter(x)} */
public static final Rop MONITOR_ENTER =
new Rop(RegOps.MONITOR_ENTER, Type.VOID, StdTypeList.OBJECT,
Exceptions.LIST_Error_NullPointerException, "monitor-enter");
- /** <code>x: Object :: monitorexit(x)</code> */
+ /** {@code x: Object :: monitorexit(x)} */
public static final Rop MONITOR_EXIT =
new Rop(RegOps.MONITOR_EXIT, Type.VOID, StdTypeList.OBJECT,
Exceptions.LIST_Error_Null_IllegalMonitorStateException,
"monitor-exit");
- /** <code>r,y: int; x: int[] :: r = x[y]</code> */
+ /** {@code r,y: int; x: int[] :: r = x[y]} */
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]</code> */
+ /** {@code r: long; x: long[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: float; x: float[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: double; x: double[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: Object; x: Object[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: boolean; x: boolean[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: byte; x: byte[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: char; x: char[]; y: int :: r = x[y]} */
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]</code> */
+ /** {@code r: short; x: short[]; y: int :: r = x[y]} */
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</code> */
+ /** {@code x,z: int; y: int[] :: y[z] = x} */
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</code> */
+ /** {@code x: long; y: long[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: float; y: float[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: double; y: double[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: Object; y: Object[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: boolean; y: boolean[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: byte; y: byte[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: char; y: char[]; z: int :: y[z] = x} */
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</code> */
+ /** {@code x: short; y: short[]; z: int :: y[z] = x} */
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)</code> (allocate heap space for an object)
+ * {@code T: any non-array object type :: r =
+ * alloc(T)} (allocate heap space for an object)
*/
public static final Rop NEW_INSTANCE =
new Rop(RegOps.NEW_INSTANCE, Type.OBJECT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "new-instance");
- /** <code>r: int[]; x: int :: r = new int[x]</code> */
+ /** {@code r: int[]; x: int :: r = new int[x]} */
public static final Rop NEW_ARRAY_INT =
new Rop(RegOps.NEW_ARRAY, Type.INT_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-int");
- /** <code>r: long[]; x: int :: r = new long[x]</code> */
+ /** {@code r: long[]; x: int :: r = new long[x]} */
public static final Rop NEW_ARRAY_LONG =
new Rop(RegOps.NEW_ARRAY, Type.LONG_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-long");
- /** <code>r: float[]; x: int :: r = new float[x]</code> */
+ /** {@code r: float[]; x: int :: r = new float[x]} */
public static final Rop NEW_ARRAY_FLOAT =
new Rop(RegOps.NEW_ARRAY, Type.FLOAT_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-float");
- /** <code>r: double[]; x: int :: r = new double[x]</code> */
+ /** {@code r: double[]; x: int :: r = new double[x]} */
public static final Rop NEW_ARRAY_DOUBLE =
new Rop(RegOps.NEW_ARRAY, Type.DOUBLE_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-double");
- /** <code>r: boolean[]; x: int :: r = new boolean[x]</code> */
+ /** {@code r: boolean[]; x: int :: r = new boolean[x]} */
public static final Rop NEW_ARRAY_BOOLEAN =
new Rop(RegOps.NEW_ARRAY, Type.BOOLEAN_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-boolean");
- /** <code>r: byte[]; x: int :: r = new byte[x]</code> */
+ /** {@code r: byte[]; x: int :: r = new byte[x]} */
public static final Rop NEW_ARRAY_BYTE =
new Rop(RegOps.NEW_ARRAY, Type.BYTE_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-byte");
- /** <code>r: char[]; x: int :: r = new char[x]</code> */
+ /** {@code r: char[]; x: int :: r = new char[x]} */
public static final Rop NEW_ARRAY_CHAR =
new Rop(RegOps.NEW_ARRAY, Type.CHAR_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-char");
- /** <code>r: short[]; x: int :: r = new short[x]</code> */
+ /** {@code r: short[]; x: int :: r = new short[x]} */
public static final Rop NEW_ARRAY_SHORT =
new Rop(RegOps.NEW_ARRAY, Type.SHORT_ARRAY, StdTypeList.INT,
Exceptions.LIST_Error_NegativeArraySizeException,
"new-array-short");
/**
- * <code>T: any non-array object type; x: Object :: (T) x</code> (can
- * throw <code>ClassCastException</code>)
+ * {@code T: any non-array object type; x: Object :: (T) x} (can
+ * throw {@code ClassCastException})
*/
public static final Rop CHECK_CAST =
new Rop(RegOps.CHECK_CAST, Type.VOID, StdTypeList.OBJECT,
Exceptions.LIST_Error_ClassCastException, "check-cast");
/**
- * <code>T: any non-array object type; x: Object :: x instanceof
- * T</code>. Note: This is listed as throwing <code>Error</code>
+ * {@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.
*/
@@ -822,24 +822,24 @@
Exceptions.LIST_Error, "instance-of");
/**
- * <code>r: int; x: Object; f: instance field spec of
- * type int :: r = x.f</code>
+ * {@code r: int; x: Object; f: instance field spec of
+ * type int :: r = x.f}
*/
public static final Rop GET_FIELD_INT =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
Exceptions.LIST_Error_NullPointerException, "get-field-int");
/**
- * <code>r: long; x: Object; f: instance field spec of
- * type long :: r = x.f</code>
+ * {@code r: long; x: Object; f: instance field spec of
+ * type long :: r = x.f}
*/
public static final Rop GET_FIELD_LONG =
new Rop(RegOps.GET_FIELD, Type.LONG, StdTypeList.OBJECT,
Exceptions.LIST_Error_NullPointerException, "get-field-long");
/**
- * <code>r: float; x: Object; f: instance field spec of
- * type float :: r = x.f</code>
+ * {@code r: float; x: Object; f: instance field spec of
+ * type float :: r = x.f}
*/
public static final Rop GET_FIELD_FLOAT =
new Rop(RegOps.GET_FIELD, Type.FLOAT, StdTypeList.OBJECT,
@@ -847,8 +847,8 @@
"get-field-float");
/**
- * <code>r: double; x: Object; f: instance field spec of
- * type double :: r = x.f</code>
+ * {@code r: double; x: Object; f: instance field spec of
+ * type double :: r = x.f}
*/
public static final Rop GET_FIELD_DOUBLE =
new Rop(RegOps.GET_FIELD, Type.DOUBLE, StdTypeList.OBJECT,
@@ -856,8 +856,8 @@
"get-field-double");
/**
- * <code>r: Object; x: Object; f: instance field spec of
- * type Object :: r = x.f</code>
+ * {@code r: Object; x: Object; f: instance field spec of
+ * type Object :: r = x.f}
*/
public static final Rop GET_FIELD_OBJECT =
new Rop(RegOps.GET_FIELD, Type.OBJECT, StdTypeList.OBJECT,
@@ -865,8 +865,8 @@
"get-field-object");
/**
- * <code>r: boolean; x: Object; f: instance field spec of
- * type boolean :: r = x.f</code>
+ * {@code r: boolean; x: Object; f: instance field spec of
+ * type boolean :: r = x.f}
*/
public static final Rop GET_FIELD_BOOLEAN =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -874,8 +874,8 @@
"get-field-boolean");
/**
- * <code>r: byte; x: Object; f: instance field spec of
- * type byte :: r = x.f</code>
+ * {@code r: byte; x: Object; f: instance field spec of
+ * type byte :: r = x.f}
*/
public static final Rop GET_FIELD_BYTE =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -883,8 +883,8 @@
"get-field-byte");
/**
- * <code>r: char; x: Object; f: instance field spec of
- * type char :: r = x.f</code>
+ * {@code r: char; x: Object; f: instance field spec of
+ * type char :: r = x.f}
*/
public static final Rop GET_FIELD_CHAR =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
@@ -892,105 +892,78 @@
"get-field-char");
/**
- * <code>r: short; x: Object; f: instance field spec of
- * type short :: r = x.f</code>
+ * {@code r: short; x: Object; f: instance field spec of
+ * type short :: r = x.f}
*/
public static final Rop GET_FIELD_SHORT =
new Rop(RegOps.GET_FIELD, Type.INT, StdTypeList.OBJECT,
Exceptions.LIST_Error_NullPointerException,
"get-field-short");
- /**
- * <code>r: int; f: static field spec of type int :: r =
- * f</code>
- */
+ /** {@code r: int; f: static field spec of type int :: r = f} */
public static final Rop GET_STATIC_INT =
new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-static-int");
- /**
- * <code>r: long; f: static field spec of type long :: r =
- * f</code>
- */
+ /** {@code r: long; f: static field spec of type long :: r = f} */
public static final Rop GET_STATIC_LONG =
new Rop(RegOps.GET_STATIC, Type.LONG, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-static-long");
- /**
- * <code>r: float; f: static field spec of type float :: r =
- * f</code>
- */
+ /** {@code r: float; f: static field spec of type float :: r = f} */
public static final Rop GET_STATIC_FLOAT =
new Rop(RegOps.GET_STATIC, Type.FLOAT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-static-float");
- /**
- * <code>r: double; f: static field spec of type double :: r =
- * f</code>
- */
+ /** {@code r: double; f: static field spec of type double :: r = f} */
public static final Rop GET_STATIC_DOUBLE =
new Rop(RegOps.GET_STATIC, Type.DOUBLE, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-static-double");
- /**
- * <code>r: Object; f: static field spec of type Object :: r =
- * f</code>
- */
+ /** {@code r: Object; f: static field spec of type Object :: r = f} */
public static final Rop GET_STATIC_OBJECT =
new Rop(RegOps.GET_STATIC, Type.OBJECT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-static-object");
- /**
- * <code>r: boolean; f: static field spec of type boolean :: r =
- * f</code>
- */
+ /** {@code r: boolean; f: static field spec of type boolean :: r = f} */
public static final Rop GET_STATIC_BOOLEAN =
new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-field-boolean");
- /**
- * <code>r: byte; f: static field spec of type byte :: r =
- * f</code>
- */
+ /** {@code r: byte; f: static field spec of type byte :: r = f} */
public static final Rop GET_STATIC_BYTE =
new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-field-byte");
- /**
- * <code>r: char; f: static field spec of type char :: r =
- * f</code>
- */
+ /** {@code r: char; f: static field spec of type char :: r = f} */
public static final Rop GET_STATIC_CHAR =
new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-field-char");
- /**
- * <code>r: short; f: static field spec of type short :: r =
- * f</code>
- */
+ /** {@code r: short; f: static field spec of type short :: r = f} */
public static final Rop GET_STATIC_SHORT =
new Rop(RegOps.GET_STATIC, Type.INT, StdTypeList.EMPTY,
Exceptions.LIST_Error, "get-field-short");
/**
- * <code>x: int; y: Object; f: instance field spec of type
- * int :: y.f = x</code>
+ * {@code x: int; y: Object; f: instance field spec of type
+ * int :: y.f = x}
*/
public static final Rop PUT_FIELD_INT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
Exceptions.LIST_Error_NullPointerException, "put-field-int");
/**
- * <code>x: long; y: Object; f: instance field spec of type
- * long :: y.f = x</code>
+ * {@code x: long; y: Object; f: instance field spec of type
+ * long :: y.f = x}
*/
public static final Rop PUT_FIELD_LONG =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.LONG_OBJECT,
Exceptions.LIST_Error_NullPointerException, "put-field-long");
/**
- * <code>x: float; y: Object; f: instance field spec of type
- * float :: y.f = x</code>
+ * {@code x: float; y: Object; f: instance field spec of type
+ * float :: y.f = x}
*/
public static final Rop PUT_FIELD_FLOAT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.FLOAT_OBJECT,
@@ -998,8 +971,8 @@
"put-field-float");
/**
- * <code>x: double; y: Object; f: instance field spec of type
- * double :: y.f = x</code>
+ * {@code x: double; y: Object; f: instance field spec of type
+ * double :: y.f = x}
*/
public static final Rop PUT_FIELD_DOUBLE =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.DOUBLE_OBJECT,
@@ -1007,8 +980,8 @@
"put-field-double");
/**
- * <code>x: Object; y: Object; f: instance field spec of type
- * Object :: y.f = x</code>
+ * {@code x: Object; y: Object; f: instance field spec of type
+ * Object :: y.f = x}
*/
public static final Rop PUT_FIELD_OBJECT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.OBJECT_OBJECT,
@@ -1016,8 +989,8 @@
"put-field-object");
/**
- * <code>x: int; y: Object; f: instance field spec of type
- * boolean :: y.f = x</code>
+ * {@code x: int; y: Object; f: instance field spec of type
+ * boolean :: y.f = x}
*/
public static final Rop PUT_FIELD_BOOLEAN =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -1025,8 +998,8 @@
"put-field-boolean");
/**
- * <code>x: int; y: Object; f: instance field spec of type
- * byte :: y.f = x</code>
+ * {@code x: int; y: Object; f: instance field spec of type
+ * byte :: y.f = x}
*/
public static final Rop PUT_FIELD_BYTE =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -1034,8 +1007,8 @@
"put-field-byte");
/**
- * <code>x: int; y: Object; f: instance field spec of type
- * char :: y.f = x</code>
+ * {@code x: int; y: Object; f: instance field spec of type
+ * char :: y.f = x}
*/
public static final Rop PUT_FIELD_CHAR =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
@@ -1043,112 +1016,88 @@
"put-field-char");
/**
- * <code>x: int; y: Object; f: instance field spec of type
- * short :: y.f = x</code>
+ * {@code x: int; y: Object; f: instance field spec of type
+ * short :: y.f = x}
*/
public static final Rop PUT_FIELD_SHORT =
new Rop(RegOps.PUT_FIELD, Type.VOID, StdTypeList.INT_OBJECT,
Exceptions.LIST_Error_NullPointerException,
"put-field-short");
- /**
- * <code>f: static field spec of type int; x: int :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type int; x: int :: f = x} */
public static final Rop PUT_STATIC_INT =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
Exceptions.LIST_Error, "put-static-int");
- /**
- * <code>f: static field spec of type long; x: long :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type long; x: long :: f = x} */
public static final Rop PUT_STATIC_LONG =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.LONG,
Exceptions.LIST_Error, "put-static-long");
- /**
- * <code>f: static field spec of type float; x: float :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type float; x: float :: f = x} */
public static final Rop PUT_STATIC_FLOAT =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.FLOAT,
Exceptions.LIST_Error, "put-static-float");
- /**
- * <code>f: static field spec of type double; x: double :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type double; x: double :: f = x} */
public static final Rop PUT_STATIC_DOUBLE =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.DOUBLE,
Exceptions.LIST_Error, "put-static-double");
- /**
- * <code>f: static field spec of type Object; x: Object :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type Object; x: Object :: f = x} */
public static final Rop PUT_STATIC_OBJECT =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.OBJECT,
Exceptions.LIST_Error, "put-static-object");
/**
- * <code>f: static field spec of type boolean; x: boolean :: f =
- * x</code>
+ * {@code f: static field spec of type boolean; x: boolean :: f =
+ * x}
*/
public static final Rop PUT_STATIC_BOOLEAN =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
Exceptions.LIST_Error, "put-static-boolean");
- /**
- * <code>f: static field spec of type byte; x: byte :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type byte; x: byte :: f = x} */
public static final Rop PUT_STATIC_BYTE =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
Exceptions.LIST_Error, "put-static-byte");
- /**
- * <code>f: static field spec of type char; x: char :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type char; x: char :: f = x} */
public static final Rop PUT_STATIC_CHAR =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
Exceptions.LIST_Error, "put-static-char");
- /**
- * <code>f: static field spec of type short; x: short :: f =
- * x</code>
- */
+ /** {@code f: static field spec of type short; x: short :: f = x} */
public static final Rop PUT_STATIC_SHORT =
new Rop(RegOps.PUT_STATIC, Type.VOID, StdTypeList.INT,
Exceptions.LIST_Error, "put-static-short");
- /** <code>x: Int :: local variable begins in x */
+ /** {@code x: Int :: local variable begins in x} */
public static final Rop MARK_LOCAL_INT =
new Rop (RegOps.MARK_LOCAL, Type.VOID,
StdTypeList.INT, "mark-local-int");
- /** <code>x: Long :: local variable begins in x */
+ /** {@code x: Long :: local variable begins in x} */
public static final Rop MARK_LOCAL_LONG =
new Rop (RegOps.MARK_LOCAL, Type.VOID,
StdTypeList.LONG, "mark-local-long");
- /** <code>x: Float :: local variable begins in x */
+ /** {@code x: Float :: local variable begins in x} */
public static final Rop MARK_LOCAL_FLOAT =
new Rop (RegOps.MARK_LOCAL, Type.VOID,
StdTypeList.FLOAT, "mark-local-float");
- /** <code>x: Double :: local variable begins in x */
+ /** {@code x: Double :: local variable begins in x} */
public static final Rop MARK_LOCAL_DOUBLE =
new Rop (RegOps.MARK_LOCAL, Type.VOID,
StdTypeList.DOUBLE, "mark-local-double");
- /** <code>x: Object :: local variable begins in x */
+ /** {@code x: Object :: local variable begins in x} */
public static final Rop MARK_LOCAL_OBJECT =
new Rop (RegOps.MARK_LOCAL, Type.VOID,
StdTypeList.OBJECT, "mark-local-object");
- /** <code>T: Any primitive type; v0..vx: T :: {v0, ..., vx}</code> */
+ /** {@code T: Any primitive type; v0..vx: T :: {v0, ..., vx}} */
public static final Rop FILL_ARRAY_DATA =
new Rop(RegOps.FILL_ARRAY_DATA, Type.VOID, StdTypeList.EMPTY,
"fill-array-data");
@@ -1164,13 +1113,14 @@
* match what is returned. TODO: Revisit this issue.</p>
*
* @param opcode the opcode
- * @param dest non-null; destination type, or {@link Type#VOID} if none
- * @param sources non-null; list of source types
- * @param cst null-ok; associated constant, if any
- * @return non-null; an appropriate instance
+ * @param dest {@code non-null;} destination (result) type, or
+ * {@link Type#VOID} if none
+ * @param sources {@code non-null;} list of source types
+ * @param cst {@code null-ok;} associated constant, if any
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop ropFor(int opcode, TypeBearer dest, TypeList sources,
- Constant cst) {
+ Constant cst) {
switch (opcode) {
case RegOps.NOP: return NOP;
case RegOps.MOVE: return opMove(dest);
@@ -1216,19 +1166,31 @@
case RegOps.MONITOR_EXIT: return MONITOR_EXIT;
case RegOps.AGET: {
Type source = sources.getType(0);
+ Type componentType;
if (source == Type.KNOWN_NULL) {
- // Treat a known-null as an Object[] in this context.
- source = Type.OBJECT_ARRAY;
- }
- return opAget(source.getComponentType());
+ /*
+ * Treat a known-null as an array of the expected
+ * result type.
+ */
+ componentType = dest.getType();
+ } else {
+ componentType = source.getComponentType();
+ }
+ return opAget(componentType);
}
case RegOps.APUT: {
Type source = sources.getType(1);
+ Type componentType;
if (source == Type.KNOWN_NULL) {
- // Treat a known-null as an Object[] in this context.
- source = Type.OBJECT_ARRAY;
- }
- return opAput(source.getComponentType());
+ /*
+ * Treat a known-null as an array of the type being
+ * stored.
+ */
+ componentType = sources.getType(0);
+ } else {
+ componentType = source.getComponentType();
+ }
+ return opAput(componentType);
}
case RegOps.NEW_INSTANCE: return NEW_INSTANCE;
case RegOps.NEW_ARRAY: return opNewArray(dest.getType());
@@ -1275,11 +1237,11 @@
}
/**
- * Returns the appropriate <code>move</code> rop for the given type. The
+ * Returns the appropriate {@code move} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; type of value being moved
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being moved
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMove(TypeBearer type) {
switch (type.getBasicFrameType()) {
@@ -1295,11 +1257,11 @@
}
/**
- * Returns the appropriate <code>move-param</code> rop for the
+ * Returns the appropriate {@code move-param} rop for the
* given type. The result is a shared instance.
*
- * @param type non-null; type of value being moved
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being moved
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMoveParam(TypeBearer type) {
switch (type.getBasicFrameType()) {
@@ -1314,11 +1276,11 @@
}
/**
- * Returns the appropriate <code>move-exception</code> rop for the
+ * Returns the appropriate {@code move-exception} rop for the
* given type. The result may be a shared instance.
*
- * @param type non-null; type of the exception
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the exception
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMoveException(TypeBearer type) {
return new Rop(RegOps.MOVE_EXCEPTION, type.getType(),
@@ -1326,11 +1288,11 @@
}
/**
- * Returns the appropriate <code>move-result</code> rop for the
+ * Returns the appropriate {@code move-result} rop for the
* given type. The result may be a shared instance.
*
- * @param type non-null; type of the parameter
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the parameter
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMoveResult(TypeBearer type) {
return new Rop(RegOps.MOVE_RESULT, type.getType(),
@@ -1338,11 +1300,11 @@
}
/**
- * Returns the appropriate <code>move-result-pseudo</code> rop for the
+ * Returns the appropriate {@code move-result-pseudo} rop for the
* given type. The result may be a shared instance.
*
- * @param type non-null; type of the parameter
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the parameter
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMoveResultPseudo(TypeBearer type) {
return new Rop(RegOps.MOVE_RESULT_PSEUDO, type.getType(),
@@ -1350,11 +1312,11 @@
}
/**
- * Returns the appropriate <code>const</code> rop for the given
+ * Returns the appropriate {@code const} rop for the given
* type. The result is a shared instance.
*
- * @param type non-null; type of the constant
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the constant
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opConst(TypeBearer type) {
if (type.getType() == Type.KNOWN_NULL) {
@@ -1373,11 +1335,11 @@
}
/**
- * Returns the appropriate <code>if-eq</code> rop for the given
+ * Returns the appropriate {@code if-eq} rop for the given
* sources. The result is a shared instance.
*
- * @param types non-null; source types
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opIfEq(TypeList types) {
return pickIf(types, IF_EQZ_INT, IF_EQZ_OBJECT,
@@ -1385,11 +1347,11 @@
}
/**
- * Returns the appropriate <code>if-ne</code> rop for the given
+ * Returns the appropriate {@code if-ne} rop for the given
* sources. The result is a shared instance.
*
- * @param types non-null; source types
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opIfNe(TypeList types) {
return pickIf(types, IF_NEZ_INT, IF_NEZ_OBJECT,
@@ -1397,60 +1359,60 @@
}
/**
- * Returns the appropriate <code>if-lt</code> rop for the given
+ * Returns the appropriate {@code if-lt} rop for the given
* sources. The result is a shared instance.
*
- * @param types non-null; source types
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opIfLt(TypeList types) {
return pickIf(types, IF_LTZ_INT, null, IF_LT_INT, null);
}
/**
- * Returns the appropriate <code>if-ge</code> rop for the given
+ * Returns the appropriate {@code if-ge} rop for the given
* sources. The result is a shared instance.
*
- * @param types non-null; source types
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opIfGe(TypeList types) {
return pickIf(types, IF_GEZ_INT, null, IF_GE_INT, null);
}
/**
- * Returns the appropriate <code>if-gt</code> rop for the given
+ * Returns the appropriate {@code if-gt} rop for the given
* sources. The result is a shared instance.
*
- * @param types non-null; source types
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opIfGt(TypeList types) {
return pickIf(types, IF_GTZ_INT, null, IF_GT_INT, null);
}
/**
- * Returns the appropriate <code>if-le</code> rop for the given
+ * Returns the appropriate {@code if-le} rop for the given
* sources. The result is a shared instance.
*
- * @param types non-null; source types
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} source types
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opIfLe(TypeList types) {
return pickIf(types, IF_LEZ_INT, null, IF_LE_INT, null);
}
/**
- * Helper for all the <code>if*</code>-related methods, which
+ * 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 non-null; the types
- * @param intZ non-null; the int-to-0 comparison
- * @param objZ null-ok; the object-to-null comparison
- * @param intInt non-null; the int-to-int comparison
- * @param objObj non-null; the object-to-object comparison
- * @return non-null; the appropriate instance
+ * @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
+ * @param intInt {@code non-null;} the int-to-int comparison
+ * @param objObj {@code non-null;} the object-to-object comparison
+ * @return {@code non-null;} the appropriate instance
*/
private static Rop pickIf(TypeList types, Rop intZ, Rop objZ, Rop intInt,
Rop objObj) {
@@ -1490,11 +1452,11 @@
}
/**
- * Returns the appropriate <code>add</code> rop for the given
+ * Returns the appropriate {@code add} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opAdd(TypeList types) {
return pickBinaryOp(types, ADD_CONST_INT, ADD_CONST_LONG,
@@ -1503,11 +1465,11 @@
}
/**
- * Returns the appropriate <code>sub</code> rop for the given
+ * Returns the appropriate {@code sub} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opSub(TypeList types) {
return pickBinaryOp(types, SUB_CONST_INT, SUB_CONST_LONG,
@@ -1516,11 +1478,11 @@
}
/**
- * Returns the appropriate <code>mul</code> rop for the given
+ * Returns the appropriate {@code mul} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMul(TypeList types) {
return pickBinaryOp(types, MUL_CONST_INT, MUL_CONST_LONG,
@@ -1529,11 +1491,11 @@
}
/**
- * Returns the appropriate <code>div</code> rop for the given
+ * Returns the appropriate {@code div} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opDiv(TypeList types) {
return pickBinaryOp(types, DIV_CONST_INT, DIV_CONST_LONG,
@@ -1542,11 +1504,11 @@
}
/**
- * Returns the appropriate <code>rem</code> rop for the given
+ * Returns the appropriate {@code rem} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opRem(TypeList types) {
return pickBinaryOp(types, REM_CONST_INT, REM_CONST_LONG,
@@ -1555,11 +1517,11 @@
}
/**
- * Returns the appropriate <code>and</code> rop for the given
+ * Returns the appropriate {@code and} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opAnd(TypeList types) {
return pickBinaryOp(types, AND_CONST_INT, AND_CONST_LONG, null, null,
@@ -1567,11 +1529,11 @@
}
/**
- * Returns the appropriate <code>or</code> rop for the given
+ * Returns the appropriate {@code or} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opOr(TypeList types) {
return pickBinaryOp(types, OR_CONST_INT, OR_CONST_LONG, null, null,
@@ -1579,11 +1541,11 @@
}
/**
- * Returns the appropriate <code>xor</code> rop for the given
+ * Returns the appropriate {@code xor} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opXor(TypeList types) {
return pickBinaryOp(types, XOR_CONST_INT, XOR_CONST_LONG, null, null,
@@ -1591,11 +1553,11 @@
}
/**
- * Returns the appropriate <code>shl</code> rop for the given
+ * Returns the appropriate {@code shl} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opShl(TypeList types) {
return pickBinaryOp(types, SHL_CONST_INT, SHL_CONST_LONG, null, null,
@@ -1603,11 +1565,11 @@
}
/**
- * Returns the appropriate <code>shr</code> rop for the given
+ * Returns the appropriate {@code shr} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opShr(TypeList types) {
return pickBinaryOp(types, SHR_CONST_INT, SHR_CONST_LONG, null, null,
@@ -1615,11 +1577,11 @@
}
/**
- * Returns the appropriate <code>ushr</code> rop for the given
+ * Returns the appropriate {@code ushr} rop for the given
* types. The result is a shared instance.
*
- * @param types non-null; types of the sources
- * @return non-null; an appropriate instance
+ * @param types {@code non-null;} types of the sources
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opUshr(TypeList types) {
return pickBinaryOp(types, USHR_CONST_INT, USHR_CONST_LONG, null, null,
@@ -1630,16 +1592,16 @@
* Returns the appropriate binary arithmetic rop for the given type
* and arguments. The result is a shared instance.
*
- * @param types non-null; sources of the operation
- * @param int1 non-null; the int-to-constant rop
- * @param long1 non-null; the long-to-constant rop
- * @param float1 null-ok; the float-to-constant rop, if any
- * @param double1 null-ok; the double-to-constant rop, if any
- * @param int2 non-null; the int-to-int rop
- * @param long2 non-null; the long-to-long or long-to-int rop
- * @param float2 null-ok; the float-to-float rop, if any
- * @param double2 null-ok; the double-to-double rop, if any
- * @return non-null; an appropriate 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
+ * @param float1 {@code null-ok;} the float-to-constant rop, if any
+ * @param double1 {@code null-ok;} the double-to-constant rop, if any
+ * @param int2 {@code non-null;} the int-to-int rop
+ * @param long2 {@code non-null;} the long-to-long or long-to-int rop
+ * @param float2 {@code null-ok;} the float-to-float rop, if any
+ * @param double2 {@code null-ok;} the double-to-double rop, if any
+ * @return {@code non-null;} an appropriate instance
*/
private static Rop pickBinaryOp(TypeList types, Rop int1, Rop long1,
Rop float1, Rop double1, Rop int2,
@@ -1676,11 +1638,11 @@
}
/**
- * Returns the appropriate <code>neg</code> rop for the given type. The
+ * Returns the appropriate {@code neg} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; type of value being operated on
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being operated on
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opNeg(TypeBearer type) {
switch (type.getBasicFrameType()) {
@@ -1694,11 +1656,11 @@
}
/**
- * Returns the appropriate <code>not</code> rop for the given type. The
+ * Returns the appropriate {@code not} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; type of value being operated on
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being operated on
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opNot(TypeBearer type) {
switch (type.getBasicFrameType()) {
@@ -1710,11 +1672,11 @@
}
/**
- * Returns the appropriate <code>cmpl</code> rop for the given type. The
+ * Returns the appropriate {@code cmpl} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; type of value being compared
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being compared
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opCmpl(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1727,11 +1689,11 @@
}
/**
- * Returns the appropriate <code>cmpg</code> rop for the given type. The
+ * Returns the appropriate {@code cmpg} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; type of value being compared
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being compared
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opCmpg(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1743,12 +1705,12 @@
}
/**
- * Returns the appropriate <code>conv</code> rop for the given types. The
+ * Returns the appropriate {@code conv} rop for the given types. The
* result is a shared instance.
*
- * @param dest non-null; target value type
- * @param source non-null; source value type
- * @return non-null; an appropriate instance
+ * @param dest {@code non-null;} target value type
+ * @param source {@code non-null;} source value type
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opConv(TypeBearer dest, TypeBearer source) {
int dbt = dest.getBasicFrameType();
@@ -1788,11 +1750,11 @@
}
/**
- * Returns the appropriate <code>return</code> rop for the given type. The
+ * Returns the appropriate {@code return} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; type of value being returned
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being returned
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opReturn(TypeBearer type) {
switch (type.getBasicFrameType()) {
@@ -1808,11 +1770,11 @@
}
/**
- * Returns the appropriate <code>aget</code> rop for the given type. The
+ * Returns the appropriate {@code aget} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; element type of array being accessed
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} element type of array being accessed
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opAget(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1831,11 +1793,11 @@
}
/**
- * Returns the appropriate <code>aput</code> rop for the given type. The
+ * Returns the appropriate {@code aput} rop for the given type. The
* result is a shared instance.
*
- * @param type non-null; element type of array being accessed
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} element type of array being accessed
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opAput(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1854,11 +1816,11 @@
}
/**
- * Returns the appropriate <code>new-array</code> rop for the given
+ * Returns the appropriate {@code new-array} rop for the given
* type. The result is a shared instance.
*
- * @param arrayType non-null; array type of array being created
- * @return non-null; an appropriate instance
+ * @param arrayType {@code non-null;} array type of array being created
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opNewArray(TypeBearer arrayType) {
Type type = arrayType.getType();
@@ -1884,12 +1846,12 @@
}
/**
- * Returns the appropriate <code>filled-new-array</code> rop for the given
+ * Returns the appropriate {@code filled-new-array} rop for the given
* type. The result may be a shared instance.
*
- * @param arrayType non-null; type of array being created
- * @param count >= 0; number of elements that the array should have
- * @return non-null; an appropriate 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
*/
public static Rop opFilledNewArray(TypeBearer arrayType, int count) {
Type type = arrayType.getType();
@@ -1916,11 +1878,11 @@
}
/**
- * Returns the appropriate <code>get-field</code> rop for the given
+ * Returns the appropriate {@code get-field} rop for the given
* type. The result is a shared instance.
*
- * @param type non-null; type of the field in question
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opGetField(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1939,11 +1901,11 @@
}
/**
- * Returns the appropriate <code>put-field</code> rop for the given
+ * Returns the appropriate {@code put-field} rop for the given
* type. The result is a shared instance.
*
- * @param type non-null; type of the field in question
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opPutField(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1962,11 +1924,11 @@
}
/**
- * Returns the appropriate <code>get-static</code> rop for the given
+ * Returns the appropriate {@code get-static} rop for the given
* type. The result is a shared instance.
*
- * @param type non-null; type of the field in question
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opGetStatic(TypeBearer type) {
switch (type.getBasicType()) {
@@ -1985,11 +1947,11 @@
}
/**
- * Returns the appropriate <code>put-static</code> rop for the given
+ * Returns the appropriate {@code put-static} rop for the given
* type. The result is a shared instance.
*
- * @param type non-null; type of the field in question
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of the field in question
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opPutStatic(TypeBearer type) {
switch (type.getBasicType()) {
@@ -2008,11 +1970,11 @@
}
/**
- * Returns the appropriate <code>invoke-static</code> rop for the
+ * Returns the appropriate {@code invoke-static} rop for the
* given type. The result is typically a newly-allocated instance.
*
- * @param meth non-null; descriptor of the method
- * @return non-null; an appropriate instance
+ * @param meth {@code non-null;} descriptor of the method
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opInvokeStatic(Prototype meth) {
return new Rop(RegOps.INVOKE_STATIC,
@@ -2021,12 +1983,12 @@
}
/**
- * Returns the appropriate <code>invoke-virtual</code> rop for the
+ * Returns the appropriate {@code invoke-virtual} rop for the
* given type. The result is typically a newly-allocated instance.
*
- * @param meth non-null; descriptor of the method, including the
- * <code>this</code> parameter
- * @return non-null; an appropriate instance
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opInvokeVirtual(Prototype meth) {
return new Rop(RegOps.INVOKE_VIRTUAL,
@@ -2035,12 +1997,12 @@
}
/**
- * Returns the appropriate <code>invoke-super</code> rop for the
+ * Returns the appropriate {@code invoke-super} rop for the
* given type. The result is typically a newly-allocated instance.
*
- * @param meth non-null; descriptor of the method, including the
- * <code>this</code> parameter
- * @return non-null; an appropriate instance
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opInvokeSuper(Prototype meth) {
return new Rop(RegOps.INVOKE_SUPER,
@@ -2049,12 +2011,12 @@
}
/**
- * Returns the appropriate <code>invoke-direct</code> rop for the
+ * Returns the appropriate {@code invoke-direct} rop for the
* given type. The result is typically a newly-allocated instance.
*
- * @param meth non-null; descriptor of the method, including the
- * <code>this</code> parameter
- * @return non-null; an appropriate instance
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opInvokeDirect(Prototype meth) {
return new Rop(RegOps.INVOKE_DIRECT,
@@ -2063,12 +2025,12 @@
}
/**
- * Returns the appropriate <code>invoke-interface</code> rop for the
+ * Returns the appropriate {@code invoke-interface} rop for the
* given type. The result is typically a newly-allocated instance.
*
- * @param meth non-null; descriptor of the method, including the
- * <code>this</code> parameter
- * @return non-null; an appropriate instance
+ * @param meth {@code non-null;} descriptor of the method, including the
+ * {@code this} parameter
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opInvokeInterface(Prototype meth) {
return new Rop(RegOps.INVOKE_INTERFACE,
@@ -2077,11 +2039,11 @@
}
/**
- * Returns the appropriate <code>mark-local</code> rop for the given type.
+ * Returns the appropriate {@code mark-local} rop for the given type.
* The result is a shared instance.
*
- * @param type non-null; type of value being marked
- * @return non-null; an appropriate instance
+ * @param type {@code non-null;} type of value being marked
+ * @return {@code non-null;} an appropriate instance
*/
public static Rop opMarkLocal(TypeBearer type) {
switch (type.getBasicFrameType()) {
@@ -2105,7 +2067,7 @@
/**
* Throws the right exception to complain about a bogus type.
*
- * @param type non-null; the bad type
+ * @param type {@code non-null;} the bad type
* @return never
*/
private static Rop throwBadType(TypeBearer type) {
@@ -2115,7 +2077,7 @@
/**
* Throws the right exception to complain about a bogus list of types.
*
- * @param types non-null; the bad types
+ * @param types {@code non-null;} the bad types
* @return never
*/
private static Rop throwBadTypes(TypeList types) {
diff --git a/dx/src/com/android/dx/rop/code/SourcePosition.java b/dx/src/com/android/dx/rop/code/SourcePosition.java
index da66c7d..f32caa1 100644
--- a/dx/src/com/android/dx/rop/code/SourcePosition.java
+++ b/dx/src/com/android/dx/rop/code/SourcePosition.java
@@ -24,21 +24,21 @@
* line number and original bytecode address.
*/
public final class SourcePosition {
- /** non-null; convenient "no information known" instance */
+ /** {@code non-null;} convenient "no information known" instance */
public static final SourcePosition NO_INFO =
new SourcePosition(null, -1, -1);
- /** null-ok; name of the file of origin or <code>null</code> if unknown */
+ /** {@code null-ok;} name of the file of origin or {@code null} if unknown */
private final CstUtf8 sourceFile;
/**
- * >= -1; the bytecode address, or <code>-1</code> if that
+ * {@code >= -1;} the bytecode address, or {@code -1} if that
* information is unknown
*/
private final int address;
/**
- * >= -1; the line number, or <code>-1</code> if that
+ * {@code >= -1;} the line number, or {@code -1} if that
* information is unknown
*/
private final int line;
@@ -46,11 +46,11 @@
/**
* Constructs an instance.
*
- * @param sourceFile null-ok; name of the file of origin or
- * <code>null</code> if unknown
- * @param address >= -1; original bytecode address or <code>-1</code>
+ * @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}
* if unknown
- * @param line >= -1; original line number or <code>-1</code> if
+ * @param line {@code >= -1;} original line number or {@code -1} if
* unknown
*/
public SourcePosition(CstUtf8 sourceFile, int address, int line) {
@@ -118,8 +118,8 @@
* Returns whether the lines match between this instance and
* the one given.
*
- * @param other non-null; the instance to compare to
- * @return <code>true</code> iff the lines match
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code true} iff the lines match
*/
public boolean sameLine(SourcePosition other) {
return (line == other.line);
@@ -129,8 +129,8 @@
* Returns whether the lines and files match between this instance and
* the one given.
*
- * @param other non-null; the instance to compare to
- * @return <code>true</code> iff the lines and files match
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code true} iff the lines and files match
*/
public boolean sameLineAndFile(SourcePosition other) {
return (line == other.line) &&
@@ -141,7 +141,7 @@
/**
* Gets the source file, if known.
*
- * @return null-ok; the source file or <code>null</code> if unknown
+ * @return {@code null-ok;} the source file or {@code null} if unknown
*/
public CstUtf8 getSourceFile() {
return sourceFile;
@@ -150,7 +150,7 @@
/**
* Gets the original bytecode address.
*
- * @return >= -1; the address or <code>-1</code> if unknown
+ * @return {@code >= -1;} the address or {@code -1} if unknown
*/
public int getAddress() {
return address;
@@ -159,7 +159,7 @@
/**
* Gets the original line number.
*
- * @return >= -1; the original line number or <code>-1</code> if
+ * @return {@code >= -1;} the original line number or {@code -1} if
* unknown
*/
public int getLine() {
diff --git a/dx/src/com/android/dx/rop/code/SwitchInsn.java b/dx/src/com/android/dx/rop/code/SwitchInsn.java
index fdf1a46..586205b 100644
--- a/dx/src/com/android/dx/rop/code/SwitchInsn.java
+++ b/dx/src/com/android/dx/rop/code/SwitchInsn.java
@@ -26,17 +26,17 @@
*/
public final class SwitchInsn
extends Insn {
- /** non-null; list of switch cases */
+ /** {@code non-null;} list of switch cases */
private final IntList cases;
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param result null-ok; spec for the result, if any
- * @param sources non-null; specs for all the sources
- * @param cases non-null; list of switch cases
+ * @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
+ * @param sources {@code non-null;} specs for all the sources
+ * @param cases {@code non-null;} list of switch cases
*/
public SwitchInsn(Rop opcode, SourcePosition position, RegisterSpec result,
RegisterSpecList sources, IntList cases) {
@@ -90,7 +90,7 @@
* {@inheritDoc}
*
* <p> SwitchInsn always compares false. The current use for this method
- * never encounters <code>SwitchInsn</code>s
+ * never encounters {@code SwitchInsn}s
*/
@Override
public boolean contentEquals(Insn b) {
@@ -111,7 +111,7 @@
/**
* Gets the list of switch cases.
*
- * @return non-null; the case list
+ * @return {@code non-null;} the case list
*/
public IntList getCases() {
return cases;
diff --git a/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java b/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
index 49ebc91..b14e758 100644
--- a/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
+++ b/dx/src/com/android/dx/rop/code/ThrowingCstInsn.java
@@ -26,17 +26,17 @@
*/
public final class ThrowingCstInsn
extends CstInsn {
- /** non-null; list of exceptions caught */
+ /** {@code non-null;} list of exceptions caught */
private final TypeList catches;
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param sources non-null; specs for all the sources
- * @param catches non-null; list of exceptions caught
- * @param cst non-null; the constant
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param sources {@code non-null;} specs for all the sources
+ * @param catches {@code non-null;} list of exceptions caught
+ * @param cst {@code non-null;} the constant
*/
public ThrowingCstInsn(Rop opcode, SourcePosition position,
RegisterSpecList sources,
diff --git a/dx/src/com/android/dx/rop/code/ThrowingInsn.java b/dx/src/com/android/dx/rop/code/ThrowingInsn.java
index 24a5bed..78dc874 100644
--- a/dx/src/com/android/dx/rop/code/ThrowingInsn.java
+++ b/dx/src/com/android/dx/rop/code/ThrowingInsn.java
@@ -20,22 +20,22 @@
import com.android.dx.rop.type.TypeList;
/**
- * Instruction which possibly throws. The <code>successors</code> list in the
+ * Instruction which possibly throws. The {@code successors} list in the
* basic block an instance of this class is inside corresponds in-order to
* the list of exceptions handled by this instruction, with the
* no-exception case appended as the final target.
*/
public final class ThrowingInsn
extends Insn {
- /** non-null; list of exceptions caught */
+ /** {@code non-null;} list of exceptions caught */
private final TypeList catches;
/**
* Gets the string form of a register spec list to be used as a catches
* list.
*
- * @param catches non-null; the catches list
- * @return non-null; the string form
+ * @param catches {@code non-null;} the catches list
+ * @return {@code non-null;} the string form
*/
public static String toCatchString(TypeList catches) {
StringBuffer sb = new StringBuffer(100);
@@ -54,10 +54,10 @@
/**
* Constructs an instance.
*
- * @param opcode non-null; the opcode
- * @param position non-null; source position
- * @param sources non-null; specs for all the sources
- * @param catches non-null; list of exceptions caught
+ * @param opcode {@code non-null;} the opcode
+ * @param position {@code non-null;} source position
+ * @param sources {@code non-null;} specs for all the sources
+ * @param catches {@code non-null;} list of exceptions caught
*/
public ThrowingInsn(Rop opcode, SourcePosition position,
RegisterSpecList sources,
diff --git a/dx/src/com/android/dx/rop/code/TranslationAdvice.java b/dx/src/com/android/dx/rop/code/TranslationAdvice.java
index 8c2cde9..832d84d 100644
--- a/dx/src/com/android/dx/rop/code/TranslationAdvice.java
+++ b/dx/src/com/android/dx/rop/code/TranslationAdvice.java
@@ -30,10 +30,10 @@
* last argument must have a type which indicates it is a known constant.)
* The instruction associated must have exactly two sources.
*
- * @param opcode non-null; the opcode
- * @param sourceA non-null; the first source
- * @param sourceB non-null; the second source
- * @return <code>true</code> iff the target can represent the operation
+ * @param opcode {@code non-null;} the opcode
+ * @param sourceA {@code non-null;} the first source
+ * @param sourceB {@code non-null;} the second source
+ * @return {@code true} iff the target can represent the operation
* using a constant for the last argument
*/
public boolean hasConstantOperation(Rop opcode,
@@ -43,9 +43,9 @@
* Returns true if the translation target requires the sources of the
* specified opcode to be in order and contiguous (eg, for an invoke-range)
*
- * @param opcode non-null; opcode
- * @param sources non-null; source list
- * @return <code>true</code> iff the target requires the sources to be
+ * @param opcode {@code non-null;} opcode
+ * @param sources {@code non-null;} source list
+ * @return {@code true} iff the target requires the sources to be
* in order and contiguous.
*/
public boolean requiresSourcesInOrder(Rop opcode, RegisterSpecList sources);
diff --git a/dx/src/com/android/dx/rop/cst/Constant.java b/dx/src/com/android/dx/rop/cst/Constant.java
index 0f44010..64231d3 100644
--- a/dx/src/com/android/dx/rop/cst/Constant.java
+++ b/dx/src/com/android/dx/rop/cst/Constant.java
@@ -24,11 +24,11 @@
public abstract class Constant
implements ToHuman, Comparable<Constant> {
/**
- * Returns <code>true</code> if this instance is a category-2 constant,
+ * Returns {@code true} if this instance is a category-2 constant,
* meaning it takes up two slots in the constant pool, or
- * <code>false</code> if this instance is category-1.
+ * {@code false} if this instance is category-1.
*
- * @return <code>true</code> iff this instance is category-2
+ * @return {@code true} iff this instance is category-2
*/
public abstract boolean isCategory2();
@@ -36,7 +36,7 @@
* Returns the human name for the particular type of constant
* this instance is.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public abstract String typeName();
@@ -60,8 +60,8 @@
* Compare the values of this and another instance, which are guaranteed
* to be of the same class. Subclasses must implement this.
*
- * @param other non-null; the instance to compare to
- * @return <code>-1</code>, <code>0</code>, or <code>1</code>, as usual
+ * @param other {@code non-null;} the instance to compare to
+ * @return {@code -1}, {@code 0}, or {@code 1}, as usual
* for a comparison
*/
protected abstract int compareTo0(Constant other);
diff --git a/dx/src/com/android/dx/rop/cst/ConstantPool.java b/dx/src/com/android/dx/rop/cst/ConstantPool.java
index 9a64a2a..efc394d 100644
--- a/dx/src/com/android/dx/rop/cst/ConstantPool.java
+++ b/dx/src/com/android/dx/rop/cst/ConstantPool.java
@@ -23,47 +23,47 @@
public interface ConstantPool {
/**
* Get the "size" of the constant pool. This corresponds to the
- * class file field <code>constant_pool_count</code>, and is in fact
+ * class file field {@code constant_pool_count}, and is in fact
* always at least one more than the actual size of the constant pool,
- * as element <code>0</code> is always invalid.
+ * as element {@code 0} is always invalid.
*
- * @return <code>>= 1</code>; the size
+ * @return {@code >= 1;} the size
*/
public int size();
/**
- * Get the <code>n</code>th entry in the constant pool, which must
+ * Get the {@code n}th entry in the constant pool, which must
* be valid.
*
- * @param n <code>n >= 0, n < size()</code>; the constant pool index
- * @return non-null; the corresponding entry
- * @throws IllegalArgumentException thrown if <code>n</code> is
+ * @param n {@code n >= 0, n < size();} the constant pool index
+ * @return {@code non-null;} the corresponding entry
+ * @throws IllegalArgumentException thrown if {@code n} is
* in-range but invalid
*/
public Constant get(int n);
/**
- * Get the <code>n</code>th entry in the constant pool, which must
- * be valid unless <code>n == 0</code>, in which case <code>null</code>
+ * Get the {@code n}th entry in the constant pool, which must
+ * be valid unless {@code n == 0}, in which case {@code null}
* is returned.
*
- * @param n <code>n >= 0, n < size()</code>; the constant pool index
- * @return null-ok; the corresponding entry, if <code>n != 0</code>
- * @throws IllegalArgumentException thrown if <code>n</code> is
+ * @param n {@code n >= 0, n < size();} the constant pool index
+ * @return {@code null-ok;} the corresponding entry, if {@code n != 0}
+ * @throws IllegalArgumentException thrown if {@code n} is
* in-range and non-zero but invalid
*/
public Constant get0Ok(int n);
/**
- * Get the <code>n</code>th entry in the constant pool, or
- * <code>null</code> if the index is in-range but invalid. In
- * particular, <code>null</code> is returned for index <code>0</code>
+ * Get the {@code n}th entry in the constant pool, or
+ * {@code null} if the index is in-range but invalid. In
+ * particular, {@code null} is returned for index {@code 0}
* as well as the index after any entry which is defined to take up
- * two slots (that is, <code>Long</code> and <code>Double</code>
+ * two slots (that is, {@code Long} and {@code Double}
* entries).
*
- * @param n <code>n >= 0, n < size()</code>; the constant pool index
- * @return null-ok; the corresponding entry, or <code>null</code> if
+ * @param n {@code n >= 0, n < size();} the constant pool index
+ * @return {@code null-ok;} the corresponding entry, or {@code null} if
* the index is in-range but invalid
*/
public Constant getOrNull(int n);
diff --git a/dx/src/com/android/dx/rop/cst/CstAnnotation.java b/dx/src/com/android/dx/rop/cst/CstAnnotation.java
index d6dc1f2..1385798 100644
--- a/dx/src/com/android/dx/rop/cst/CstAnnotation.java
+++ b/dx/src/com/android/dx/rop/cst/CstAnnotation.java
@@ -22,13 +22,13 @@
* Constant type that represents an annotation.
*/
public final class CstAnnotation extends Constant {
- /** non-null; the actual annotation */
+ /** {@code non-null;} the actual annotation */
private final Annotation annotation;
/**
* Constructs an instance.
*
- * @param annotation non-null; the annotation to hold
+ * @param annotation {@code non-null;} the annotation to hold
*/
public CstAnnotation(Annotation annotation) {
if (annotation == null) {
@@ -88,7 +88,7 @@
/**
* Get the underlying annotation.
*
- * @return non-null; the annotation
+ * @return {@code non-null;} the annotation
*/
public Annotation getAnnotation() {
return annotation;
diff --git a/dx/src/com/android/dx/rop/cst/CstArray.java b/dx/src/com/android/dx/rop/cst/CstArray.java
index 69c0aef..8b521bd 100644
--- a/dx/src/com/android/dx/rop/cst/CstArray.java
+++ b/dx/src/com/android/dx/rop/cst/CstArray.java
@@ -24,13 +24,13 @@
* may be of any type <i>other</i> than {@link CstUtf8}.
*/
public final class CstArray extends Constant {
- /** non-null; the actual list of contents */
+ /** {@code non-null;} the actual list of contents */
private final List list;
/**
* Constructs an instance.
*
- * @param list non-null; the actual list of contents
+ * @param list {@code non-null;} the actual list of contents
*/
public CstArray(List list) {
if (list == null) {
@@ -90,7 +90,7 @@
/**
* Get the underlying list.
*
- * @return non-null; the list
+ * @return {@code non-null;} the list
*/
public List getList() {
return list;
@@ -103,7 +103,7 @@
extends FixedSizeList implements Comparable<List> {
/**
* Constructs an instance. All indices initially contain
- * <code>null</code>.
+ * {@code null}.
*
* @param size the size of the list
*/
@@ -138,10 +138,10 @@
/**
* 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</code>.
+ * do that, this will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which index
- * @return non-null; element at that index
+ * @param n {@code >= 0, < size();} which index
+ * @return {@code non-null;} element at that index
*/
public Constant get(int n) {
return (Constant) get0(n);
@@ -150,8 +150,8 @@
/**
* Sets the element at the given index.
*
- * @param n >= 0, < size(); which index
- * @param a null-ok; the element to set at <code>n</code>
+ * @param n {@code >= 0, < size();} which index
+ * @param a {@code null-ok;} the element to set at {@code n}
*/
public void set(int n, Constant a) {
if (a instanceof CstUtf8) {
diff --git a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
index c885601..039d7ed 100644
--- a/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstBaseMethodRef.java
@@ -28,20 +28,20 @@
*/
public abstract class CstBaseMethodRef
extends CstMemberRef {
- /** non-null; the raw prototype for this method */
+ /** {@code non-null;} the raw prototype for this method */
private final Prototype prototype;
/**
- * null-ok; the prototype for this method taken to be an instance
- * method, or <code>null</code> if not yet calculated
+ * {@code null-ok;} the prototype for this method taken to be an instance
+ * method, or {@code null} if not yet calculated
*/
private Prototype instancePrototype;
/**
* Constructs an instance.
*
- * @param definingClass non-null; the type of the defining class
- * @param nat non-null; the name-and-type
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
*/
/*package*/ CstBaseMethodRef(CstType definingClass, CstNat nat) {
super(definingClass, nat);
@@ -53,9 +53,9 @@
/**
* Gets the raw prototype of this method. This doesn't include a
- * <code>this</code> argument.
+ * {@code this} argument.
*
- * @return non-null; the method prototype
+ * @return {@code non-null;} the method prototype
*/
public final Prototype getPrototype() {
return prototype;
@@ -63,14 +63,14 @@
/**
* Gets the prototype of this method as either a
- * <code>static</code> or instance method. In the case of a
- * <code>static</code> method, this is the same as the raw
+ * {@code static} or instance method. In the case of a
+ * {@code static} method, this is the same as the raw
* prototype. In the case of an instance method, this has an
- * appropriately-typed <code>this</code> argument as the first
+ * appropriately-typed {@code this} argument as the first
* one.
*
* @param isStatic whether the method should be considered static
- * @return non-null; the method prototype
+ * @return {@code non-null;} the method prototype
*/
public final Prototype getPrototype(boolean isStatic) {
if (isStatic) {
@@ -102,7 +102,7 @@
*
* In this case, this method returns the <i>return type</i> of this method.
*
- * @return non-null; the method's return type
+ * @return {@code non-null;} the method's return type
*/
public final Type getType() {
return prototype.getReturnType();
@@ -111,15 +111,15 @@
/**
* Gets the number of words of parameters required by this
* method's descriptor. Since instances of this class have no way
- * to know if they will be used in a <code>static</code> or
+ * to know if they will be used in a {@code static} or
* instance context, one has to indicate this explicitly as an
* argument. This method is just a convenient shorthand for
- * <code>getPrototype().getParameterTypes().getWordCount()</code>,
- * plus <code>1</code> if the method is to be treated as an
+ * {@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 >= 0; the argument word count
+ * @return {@code >= 0;} the argument word count
*/
public final int getParameterWordCount(boolean isStatic) {
return getPrototype(isStatic).getParameterTypes().getWordCount();
@@ -128,9 +128,9 @@
/**
* Gets whether this is a reference to an instance initialization
* method. This is just a convenient shorthand for
- * <code>getNat().isInstanceInit()</code>.
+ * {@code getNat().isInstanceInit()}.
*
- * @return <code>true</code> iff this is a reference to an
+ * @return {@code true} iff this is a reference to an
* instance initialization method
*/
public final boolean isInstanceInit() {
@@ -140,9 +140,9 @@
/**
* Gets whether this is a reference to a class initialization
* method. This is just a convenient shorthand for
- * <code>getNat().isClassInit()</code>.
+ * {@code getNat().isClassInit()}.
*
- * @return <code>true</code> iff this is a reference to an
+ * @return {@code true} iff this is a reference to an
* instance initialization method
*/
public final boolean isClassInit() {
diff --git a/dx/src/com/android/dx/rop/cst/CstBoolean.java b/dx/src/com/android/dx/rop/cst/CstBoolean.java
index ab25d5b..8c290ef 100644
--- a/dx/src/com/android/dx/rop/cst/CstBoolean.java
+++ b/dx/src/com/android/dx/rop/cst/CstBoolean.java
@@ -19,33 +19,33 @@
import com.android.dx.rop.type.Type;
/**
- * Constants of type <code>boolean</code>.
+ * Constants of type {@code boolean}.
*/
public final class CstBoolean
extends CstLiteral32 {
- /** non-null; instance representing <code>false</code> */
+ /** {@code non-null;} instance representing {@code false} */
public static final CstBoolean VALUE_FALSE = new CstBoolean(false);
- /** non-null; instance representing <code>true</code> */
+ /** {@code non-null;} instance representing {@code true} */
public static final CstBoolean VALUE_TRUE = new CstBoolean(true);
/**
* Makes an instance for the given value. This will return an
* already-allocated instance.
*
- * @param value the <code>boolean</code> value
- * @return non-null; the appropriate instance
+ * @param value the {@code boolean} value
+ * @return {@code non-null;} the appropriate instance
*/
public static CstBoolean make(boolean value) {
return value ? VALUE_TRUE : VALUE_FALSE;
}
/**
- * Makes an instance for the given <code>int</code> value. This
+ * Makes an instance for the given {@code int} value. This
* will return an already-allocated instance.
*
- * @param value must be either <code>0</code> or <code>1</code>
- * @return non-null; the appropriate instance
+ * @param value must be either {@code 0} or {@code 1}
+ * @return {@code non-null;} the appropriate instance
*/
public static CstBoolean make(int value) {
if (value == 0) {
@@ -60,7 +60,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param value the <code>boolean</code> value
+ * @param value the {@code boolean} value
*/
private CstBoolean(boolean value) {
super(value ? 1 : 0);
@@ -89,7 +89,7 @@
}
/**
- * Gets the <code>boolean</code> value.
+ * Gets the {@code boolean} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstByte.java b/dx/src/com/android/dx/rop/cst/CstByte.java
index ffc3206..a8af9f7 100644
--- a/dx/src/com/android/dx/rop/cst/CstByte.java
+++ b/dx/src/com/android/dx/rop/cst/CstByte.java
@@ -20,30 +20,30 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>byte</code>.
+ * Constants of type {@code byte}.
*/
public final class CstByte
extends CstLiteral32 {
- /** non-null; the value <code>0</code> as an instance of this class */
+ /** {@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</code> value
+ * @param value the {@code byte} value
*/
public static CstByte make(byte value) {
return new CstByte(value);
}
/**
- * Makes an instance for the given <code>int</code> value. This
+ * 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</code>
- * @return non-null; the appropriate instance
+ * @param value the value, which must be in range for a {@code byte}
+ * @return {@code non-null;} the appropriate instance
*/
public static CstByte make(int value) {
byte cast = (byte) value;
@@ -59,7 +59,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param value the <code>byte</code> value
+ * @param value the {@code byte} value
*/
private CstByte(byte value) {
super(value);
@@ -89,7 +89,7 @@
}
/**
- * Gets the <code>byte</code> value.
+ * Gets the {@code byte} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstChar.java b/dx/src/com/android/dx/rop/cst/CstChar.java
index a31bd7f..0a87cbc 100644
--- a/dx/src/com/android/dx/rop/cst/CstChar.java
+++ b/dx/src/com/android/dx/rop/cst/CstChar.java
@@ -20,30 +20,30 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>char</code>.
+ * Constants of type {@code char}.
*/
public final class CstChar
extends CstLiteral32 {
- /** non-null; the value <code>0</code> as an instance of this class */
+ /** {@code non-null;} the value {@code 0} as an instance of this class */
public static final CstChar VALUE_0 = make((char) 0);
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
*
- * @param value the <code>char</code> value
+ * @param value the {@code char} value
*/
public static CstChar make(char value) {
return new CstChar(value);
}
/**
- * Makes an instance for the given <code>int</code> value. This
+ * 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</code>
- * @return non-null; the appropriate instance
+ * @param value the value, which must be in range for a {@code char}
+ * @return {@code non-null;} the appropriate instance
*/
public static CstChar make(int value) {
char cast = (char) value;
@@ -59,7 +59,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param value the <code>char</code> value
+ * @param value the {@code char} value
*/
private CstChar(char value) {
super(value);
@@ -89,7 +89,7 @@
}
/**
- * Gets the <code>char</code> value.
+ * Gets the {@code char} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstDouble.java b/dx/src/com/android/dx/rop/cst/CstDouble.java
index 4516667..df4a2cf 100644
--- a/dx/src/com/android/dx/rop/cst/CstDouble.java
+++ b/dx/src/com/android/dx/rop/cst/CstDouble.java
@@ -20,15 +20,15 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>CONSTANT_Double_info</code>.
+ * Constants of type {@code CONSTANT_Double_info}.
*/
public final class CstDouble
extends CstLiteral64 {
- /** non-null; instance representing <code>0</code> */
+ /** {@code non-null;} instance representing {@code 0} */
public static final CstDouble VALUE_0 =
new CstDouble(Double.doubleToLongBits(0.0));
- /** non-null; instance representing <code>1</code> */
+ /** {@code non-null;} instance representing {@code 1} */
public static final CstDouble VALUE_1 =
new CstDouble(Double.doubleToLongBits(1.0));
@@ -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>double</code> value as <code>long</code> bits
+ * @param bits the {@code double} value as {@code long} bits
*/
public static CstDouble make(long bits) {
/*
@@ -49,7 +49,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param bits the <code>double</code> value as <code>long</code> bits
+ * @param bits the {@code double} value as {@code long} bits
*/
private CstDouble(long bits) {
super(bits);
@@ -80,7 +80,7 @@
}
/**
- * Gets the <code>double</code> value.
+ * Gets the {@code double} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstEnumRef.java b/dx/src/com/android/dx/rop/cst/CstEnumRef.java
index f5aec05..78cab9d 100644
--- a/dx/src/com/android/dx/rop/cst/CstEnumRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstEnumRef.java
@@ -23,13 +23,13 @@
* value of an enumerated type.
*/
public final class CstEnumRef extends CstMemberRef {
- /** null-ok; the corresponding field ref, lazily initialized */
+ /** {@code null-ok;} the corresponding field ref, lazily initialized */
private CstFieldRef fieldRef;
/**
* Constructs an instance.
*
- * @param nat non-null; the name-and-type; the defining class is derived
+ * @param nat {@code non-null;} the name-and-type; the defining class is derived
* from this
*/
public CstEnumRef(CstNat nat) {
@@ -56,7 +56,7 @@
/**
* Get a {@link CstFieldRef} that corresponds with this instance.
*
- * @return non-null; the corresponding field reference
+ * @return {@code non-null;} the corresponding field reference
*/
public CstFieldRef getFieldRef() {
if (fieldRef == null) {
diff --git a/dx/src/com/android/dx/rop/cst/CstFieldRef.java b/dx/src/com/android/dx/rop/cst/CstFieldRef.java
index 306eca9..497531f 100644
--- a/dx/src/com/android/dx/rop/cst/CstFieldRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstFieldRef.java
@@ -19,7 +19,7 @@
import com.android.dx.rop.type.Type;
/**
- * Constants of type <code>CONSTANT_Fieldref_info</code>.
+ * Constants of type {@code CONSTANT_Fieldref_info}.
*/
public final class CstFieldRef extends CstMemberRef {
/**
@@ -27,10 +27,10 @@
* field which should hold the class corresponding to a given
* primitive type. For example, if given {@link Type#INT}, this
* method returns an instance corresponding to the field
- * <code>java.lang.Integer.TYPE</code>.
+ * {@code java.lang.Integer.TYPE}.
*
- * @param primitiveType non-null; the primitive type
- * @return non-null; the corresponding static field
+ * @param primitiveType {@code non-null;} the primitive type
+ * @return {@code non-null;} the corresponding static field
*/
public static CstFieldRef forPrimitiveType(Type primitiveType) {
return new CstFieldRef(CstType.forBoxedPrimitiveType(primitiveType),
@@ -40,8 +40,8 @@
/**
* Constructs an instance.
*
- * @param definingClass non-null; the type of the defining class
- * @param nat non-null; the name-and-type
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
*/
public CstFieldRef(CstType definingClass, CstNat nat) {
super(definingClass, nat);
@@ -56,7 +56,7 @@
/**
* Returns the type of this field.
*
- * @return non-null; the field's type
+ * @return {@code non-null;} the field's type
*/
public Type getType() {
return getNat().getFieldType();
diff --git a/dx/src/com/android/dx/rop/cst/CstFloat.java b/dx/src/com/android/dx/rop/cst/CstFloat.java
index 08b7f76..531a20d 100644
--- a/dx/src/com/android/dx/rop/cst/CstFloat.java
+++ b/dx/src/com/android/dx/rop/cst/CstFloat.java
@@ -20,24 +20,24 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>CONSTANT_Float_info</code>.
+ * Constants of type {@code CONSTANT_Float_info}.
*/
public final class CstFloat
extends CstLiteral32 {
- /** non-null; instance representing <code>0</code> */
+ /** {@code non-null;} instance representing {@code 0} */
public static final CstFloat VALUE_0 = make(Float.floatToIntBits(0.0f));
- /** non-null; instance representing <code>1</code> */
+ /** {@code non-null;} instance representing {@code 1} */
public static final CstFloat VALUE_1 = make(Float.floatToIntBits(1.0f));
- /** non-null; instance representing <code>2</code> */
+ /** {@code non-null;} instance representing {@code 2} */
public static final CstFloat VALUE_2 = make(Float.floatToIntBits(2.0f));
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
*
- * @param bits the <code>float</code> value as <code>int</code> bits
+ * @param bits the {@code float} value as {@code int} bits
*/
public static CstFloat make(int bits) {
/*
@@ -50,7 +50,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param bits the <code>float</code> value as <code>int</code> bits
+ * @param bits the {@code float} value as {@code int} bits
*/
private CstFloat(int bits) {
super(bits);
@@ -81,7 +81,7 @@
}
/**
- * Gets the <code>float</code> value.
+ * Gets the {@code float} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstInteger.java b/dx/src/com/android/dx/rop/cst/CstInteger.java
index d3fafcc..8fae4fa 100644
--- a/dx/src/com/android/dx/rop/cst/CstInteger.java
+++ b/dx/src/com/android/dx/rop/cst/CstInteger.java
@@ -20,40 +20,40 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>CONSTANT_Integer_info</code>.
+ * Constants of type {@code CONSTANT_Integer_info}.
*/
public final class CstInteger
extends CstLiteral32 {
- /** non-null; array of cached instances */
+ /** {@code non-null;} array of cached instances */
private static final CstInteger[] cache = new CstInteger[511];
- /** non-null; instance representing <code>-1</code> */
+ /** {@code non-null;} instance representing {@code -1} */
public static final CstInteger VALUE_M1 = make(-1);
- /** non-null; instance representing <code>0</code> */
+ /** {@code non-null;} instance representing {@code 0} */
public static final CstInteger VALUE_0 = make(0);
- /** non-null; instance representing <code>1</code> */
+ /** {@code non-null;} instance representing {@code 1} */
public static final CstInteger VALUE_1 = make(1);
- /** non-null; instance representing <code>2</code> */
+ /** {@code non-null;} instance representing {@code 2} */
public static final CstInteger VALUE_2 = make(2);
- /** non-null; instance representing <code>3</code> */
+ /** {@code non-null;} instance representing {@code 3} */
public static final CstInteger VALUE_3 = make(3);
- /** non-null; instance representing <code>4</code> */
+ /** {@code non-null;} instance representing {@code 4} */
public static final CstInteger VALUE_4 = make(4);
- /** non-null; instance representing <code>5</code> */
+ /** {@code non-null;} instance representing {@code 5} */
public static final CstInteger VALUE_5 = make(5);
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
*
- * @param value the <code>int</code> value
- * @return non-null; the appropriate instance
+ * @param value the {@code int} value
+ * @return {@code non-null;} the appropriate instance
*/
public static CstInteger make(int value) {
/*
@@ -76,7 +76,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param value the <code>int</code> value
+ * @param value the {@code int} value
*/
private CstInteger(int value) {
super(value);
@@ -106,7 +106,7 @@
}
/**
- * Gets the <code>int</code> value.
+ * Gets the {@code int} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
index f169ec9..55a7599 100644
--- a/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstInterfaceMethodRef.java
@@ -17,12 +17,12 @@
package com.android.dx.rop.cst;
/**
- * Constants of type <code>CONSTANT_InterfaceMethodref_info</code>.
+ * Constants of type {@code CONSTANT_InterfaceMethodref_info}.
*/
public final class CstInterfaceMethodRef
extends CstBaseMethodRef {
/**
- * null-ok; normal {@link CstMethodRef} that corresponds to this
+ * {@code null-ok;} normal {@link CstMethodRef} that corresponds to this
* instance, if calculated
*/
private CstMethodRef methodRef;
@@ -30,8 +30,8 @@
/**
* Constructs an instance.
*
- * @param definingClass non-null; the type of the defining class
- * @param nat non-null; the name-and-type
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
*/
public CstInterfaceMethodRef(CstType definingClass, CstNat nat) {
super(definingClass, nat);
@@ -48,7 +48,7 @@
* Gets a normal (non-interface) {@link CstMethodRef} that corresponds to
* this instance.
*
- * @return non-null; an appropriate instance
+ * @return {@code non-null;} an appropriate instance
*/
public CstMethodRef toMethodRef() {
if (methodRef == null) {
diff --git a/dx/src/com/android/dx/rop/cst/CstKnownNull.java b/dx/src/com/android/dx/rop/cst/CstKnownNull.java
index 853e57e..09dde1b 100644
--- a/dx/src/com/android/dx/rop/cst/CstKnownNull.java
+++ b/dx/src/com/android/dx/rop/cst/CstKnownNull.java
@@ -19,10 +19,10 @@
import com.android.dx.rop.type.Type;
/**
- * Constant type to represent a known-<code>null</code> value.
+ * Constant type to represent a known-{@code null} value.
*/
public final class CstKnownNull extends CstLiteralBits {
- /** non-null; unique instance of this class */
+ /** {@code non-null;} unique instance of this class */
public static final CstKnownNull THE_ONE = new CstKnownNull();
/**
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral32.java b/dx/src/com/android/dx/rop/cst/CstLiteral32.java
index 31e96dd..c6e3021 100644
--- a/dx/src/com/android/dx/rop/cst/CstLiteral32.java
+++ b/dx/src/com/android/dx/rop/cst/CstLiteral32.java
@@ -21,13 +21,13 @@
*/
public abstract class CstLiteral32
extends CstLiteralBits {
- /** the value as <code>int</code> bits */
+ /** the value as {@code int} bits */
private final int bits;
/**
* Constructs an instance.
*
- * @param bits the value as <code>int</code> bits
+ * @param bits the value as {@code int} bits
*/
/*package*/ CstLiteral32(int bits) {
this.bits = bits;
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteral64.java b/dx/src/com/android/dx/rop/cst/CstLiteral64.java
index dd7d24d..d0b27d2 100644
--- a/dx/src/com/android/dx/rop/cst/CstLiteral64.java
+++ b/dx/src/com/android/dx/rop/cst/CstLiteral64.java
@@ -21,13 +21,13 @@
*/
public abstract class CstLiteral64
extends CstLiteralBits {
- /** the value as <code>long</code> bits */
+ /** the value as {@code long} bits */
private final long bits;
/**
* Constructs an instance.
*
- * @param bits the value as <code>long</code> bits
+ * @param bits the value as {@code long} bits
*/
/*package*/ CstLiteral64(long bits) {
this.bits = bits;
diff --git a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
index 98a3f0e..6415487 100644
--- a/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
+++ b/dx/src/com/android/dx/rop/cst/CstLiteralBits.java
@@ -23,18 +23,18 @@
extends TypedConstant {
/**
* Returns whether or not this instance's value may be accurately
- * represented as an <code>int</code>. The rule is that if there
- * is an <code>int</code> which may be sign-extended to yield this
- * instance's value, then this method returns <code>true</code>.
- * Otherwise, it returns <code>false</code>.
+ * represented as an {@code int}. The rule is that if there
+ * is an {@code int} which may be sign-extended to yield this
+ * instance's value, then this method returns {@code true}.
+ * Otherwise, it returns {@code false}.
*
- * @return <code>true</code> iff this instance fits in an <code>int</code>
+ * @return {@code true} iff this instance fits in an {@code int}
*/
public abstract boolean fitsInInt();
/**
- * Gets the value as <code>int</code> bits. If this instance contains
- * more bits than fit in an <code>int</code>, then this returns only
+ * Gets the value as {@code int} bits. If this instance contains
+ * more bits than fit in an {@code int}, then this returns only
* the low-order bits.
*
* @return the bits
@@ -42,8 +42,8 @@
public abstract int getIntBits();
/**
- * Gets the value as <code>long</code> bits. If this instance contains
- * fewer bits than fit in a <code>long</code>, then the result of this
+ * 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
diff --git a/dx/src/com/android/dx/rop/cst/CstLong.java b/dx/src/com/android/dx/rop/cst/CstLong.java
index 377eb93..c89a339 100644
--- a/dx/src/com/android/dx/rop/cst/CstLong.java
+++ b/dx/src/com/android/dx/rop/cst/CstLong.java
@@ -20,21 +20,21 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>CONSTANT_Long_info</code>.
+ * Constants of type {@code CONSTANT_Long_info}.
*/
public final class CstLong
extends CstLiteral64 {
- /** non-null; instance representing <code>0</code> */
+ /** {@code non-null;} instance representing {@code 0} */
public static final CstLong VALUE_0 = make(0);
- /** non-null; instance representing <code>1</code> */
+ /** {@code non-null;} instance representing {@code 1} */
public static final CstLong VALUE_1 = make(1);
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
*
- * @param value the <code>long</code> value
+ * @param value the {@code long} value
*/
public static CstLong make(long value) {
/*
@@ -47,7 +47,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param value the <code>long</code> value
+ * @param value the {@code long} value
*/
private CstLong(long value) {
super(value);
@@ -77,7 +77,7 @@
}
/**
- * Gets the <code>long</code> value.
+ * Gets the {@code long} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstMemberRef.java b/dx/src/com/android/dx/rop/cst/CstMemberRef.java
index dbaad47..bae47c2 100644
--- a/dx/src/com/android/dx/rop/cst/CstMemberRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstMemberRef.java
@@ -17,20 +17,20 @@
package com.android.dx.rop.cst;
/**
- * Constants of type <code>CONSTANT_*ref_info</code>.
+ * Constants of type {@code CONSTANT_*ref_info}.
*/
public abstract class CstMemberRef extends TypedConstant {
- /** non-null; the type of the defining class */
+ /** {@code non-null;} the type of the defining class */
private final CstType definingClass;
- /** non-null; the name-and-type */
+ /** {@code non-null;} the name-and-type */
private final CstNat nat;
/**
* Constructs an instance.
*
- * @param definingClass non-null; the type of the defining class
- * @param nat non-null; the name-and-type
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
*/
/*package*/ CstMemberRef(CstType definingClass, CstNat nat) {
if (definingClass == null) {
@@ -68,7 +68,7 @@
*
* <p><b>Note:</b> This implementation just compares the defining
* class and name, and it is up to subclasses to compare the rest
- * after calling <code>super.compareTo0()</code>.</p>
+ * after calling {@code super.compareTo0()}.</p>
*/
@Override
protected int compareTo0(Constant other) {
@@ -105,7 +105,7 @@
/**
* Gets the type of the defining class.
*
- * @return non-null; the type of defining class
+ * @return {@code non-null;} the type of defining class
*/
public final CstType getDefiningClass() {
return definingClass;
@@ -114,7 +114,7 @@
/**
* Gets the defining name-and-type.
*
- * @return non-null; the name-and-type
+ * @return {@code non-null;} the name-and-type
*/
public final CstNat getNat() {
return nat;
diff --git a/dx/src/com/android/dx/rop/cst/CstMethodRef.java b/dx/src/com/android/dx/rop/cst/CstMethodRef.java
index 766c9bf..77c97e9 100644
--- a/dx/src/com/android/dx/rop/cst/CstMethodRef.java
+++ b/dx/src/com/android/dx/rop/cst/CstMethodRef.java
@@ -17,15 +17,15 @@
package com.android.dx.rop.cst;
/**
- * Constants of type <code>CONSTANT_Methodref_info</code>.
+ * Constants of type {@code CONSTANT_Methodref_info}.
*/
public final class CstMethodRef
extends CstBaseMethodRef {
/**
* Constructs an instance.
*
- * @param definingClass non-null; the type of the defining class
- * @param nat non-null; the name-and-type
+ * @param definingClass {@code non-null;} the type of the defining class
+ * @param nat {@code non-null;} the name-and-type
*/
public CstMethodRef(CstType definingClass, CstNat nat) {
super(definingClass, nat);
diff --git a/dx/src/com/android/dx/rop/cst/CstNat.java b/dx/src/com/android/dx/rop/cst/CstNat.java
index 106b599..5270fd2 100644
--- a/dx/src/com/android/dx/rop/cst/CstNat.java
+++ b/dx/src/com/android/dx/rop/cst/CstNat.java
@@ -19,29 +19,29 @@
import com.android.dx.rop.type.Type;
/**
- * Constants of type <code>CONSTANT_NameAndType_info</code>.
+ * Constants of type {@code CONSTANT_NameAndType_info}.
*/
public final class CstNat extends Constant {
/**
- * non-null; the instance for name <code>TYPE</code> and descriptor
- * <code>java.lang.Class</code>, which is useful when dealing with
+ * {@code non-null;} the instance for name {@code TYPE} and descriptor
+ * {@code java.lang.Class}, which is useful when dealing with
* wrapped primitives
*/
public static final CstNat PRIMITIVE_TYPE_NAT =
new CstNat(new CstUtf8("TYPE"),
new CstUtf8("Ljava/lang/Class;"));
- /** non-null; the name */
+ /** {@code non-null;} the name */
private final CstUtf8 name;
- /** non-null; the descriptor (type) */
+ /** {@code non-null;} the descriptor (type) */
private final CstUtf8 descriptor;
/**
* Constructs an instance.
*
- * @param name non-null; the name
- * @param descriptor non-null; the descriptor
+ * @param name {@code non-null;} the name
+ * @param descriptor {@code non-null;} the descriptor
*/
public CstNat(CstUtf8 name, CstUtf8 descriptor) {
if (name == null) {
@@ -108,7 +108,7 @@
/**
* Gets the name.
*
- * @return non-null; the name
+ * @return {@code non-null;} the name
*/
public CstUtf8 getName() {
return name;
@@ -117,7 +117,7 @@
/**
* Gets the descriptor.
*
- * @return non-null; the descriptor
+ * @return {@code non-null;} the descriptor
*/
public CstUtf8 getDescriptor() {
return descriptor;
@@ -127,7 +127,7 @@
* Returns an unadorned but human-readable version of the name-and-type
* value.
*
- * @return non-null; the human form
+ * @return {@code non-null;} the human form
*/
public String toHuman() {
return name.toHuman() + ':' + descriptor.toHuman();
@@ -138,7 +138,7 @@
* This method is only valid to call if the descriptor in fact describes
* a field (and not a method).
*
- * @return non-null; the field type
+ * @return {@code non-null;} the field type
*/
public Type getFieldType() {
return Type.intern(descriptor.getString());
@@ -147,9 +147,9 @@
/**
* 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>")</code>.
+ * {@code getName().getString().equals("<init>")}.
*
- * @return <code>true</code> iff this is a reference to an
+ * @return {@code true} iff this is a reference to an
* instance initialization method
*/
public final boolean isInstanceInit() {
@@ -159,9 +159,9 @@
/**
* 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>")</code>.
+ * {@code getName().getString().equals("<clinit>")}.
*
- * @return <code>true</code> iff this is a reference to an
+ * @return {@code true} iff this is a reference to an
* instance initialization method
*/
public final boolean isClassInit() {
diff --git a/dx/src/com/android/dx/rop/cst/CstShort.java b/dx/src/com/android/dx/rop/cst/CstShort.java
index 3804254..4ac2f68 100644
--- a/dx/src/com/android/dx/rop/cst/CstShort.java
+++ b/dx/src/com/android/dx/rop/cst/CstShort.java
@@ -20,31 +20,31 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>short</code>.
+ * Constants of type {@code short}.
*/
public final class CstShort
extends CstLiteral32 {
- /** non-null; the value <code>0</code> as an instance of this class */
+ /** {@code non-null;} the value {@code 0} as an instance of this class */
public static final CstShort VALUE_0 = make((short) 0);
/**
* Makes an instance for the given value. This may (but does not
* necessarily) return an already-allocated instance.
*
- * @param value the <code>short</code> value
- * @return non-null; the appropriate instance
+ * @param value the {@code short} value
+ * @return {@code non-null;} the appropriate instance
*/
public static CstShort make(short value) {
return new CstShort(value);
}
/**
- * Makes an instance for the given <code>int</code> value. This
+ * 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</code>
- * @return non-null; the appropriate instance
+ * @param value the value, which must be in range for a {@code short}
+ * @return {@code non-null;} the appropriate instance
*/
public static CstShort make(int value) {
short cast = (short) value;
@@ -60,7 +60,7 @@
/**
* Constructs an instance. This constructor is private; use {@link #make}.
*
- * @param value the <code>short</code> value
+ * @param value the {@code short} value
*/
private CstShort(short value) {
super(value);
@@ -90,7 +90,7 @@
}
/**
- * Gets the <code>short</code> value.
+ * Gets the {@code short} value.
*
* @return the value
*/
diff --git a/dx/src/com/android/dx/rop/cst/CstString.java b/dx/src/com/android/dx/rop/cst/CstString.java
index 89a4c8b..ce00f52 100644
--- a/dx/src/com/android/dx/rop/cst/CstString.java
+++ b/dx/src/com/android/dx/rop/cst/CstString.java
@@ -19,17 +19,17 @@
import com.android.dx.rop.type.Type;
/**
- * Constants of type <code>CONSTANT_String_info</code>.
+ * Constants of type {@code CONSTANT_String_info}.
*/
public final class CstString
extends TypedConstant {
- /** non-null; the string value */
+ /** {@code non-null;} the string value */
private final CstUtf8 string;
/**
* Constructs an instance.
*
- * @param string non-null; the string value
+ * @param string {@code non-null;} the string value
*/
public CstString(CstUtf8 string) {
if (string == null) {
@@ -42,7 +42,7 @@
/**
* Constructs an instance.
*
- * @param string non-null; the string value
+ * @param string {@code non-null;} the string value
*/
public CstString(String string) {
this(new CstUtf8(string));
@@ -101,7 +101,7 @@
/**
* Gets the string value.
*
- * @return non-null; the string value
+ * @return {@code non-null;} the string value
*/
public CstUtf8 getString() {
return string;
diff --git a/dx/src/com/android/dx/rop/cst/CstType.java b/dx/src/com/android/dx/rop/cst/CstType.java
index 02df28d..6dc9867 100644
--- a/dx/src/com/android/dx/rop/cst/CstType.java
+++ b/dx/src/com/android/dx/rop/cst/CstType.java
@@ -24,69 +24,69 @@
* Constants that represent an arbitrary type (reference or primitive).
*/
public final class CstType extends TypedConstant {
- /** non-null; map of interned types */
+ /** {@code non-null;} map of interned types */
private static final HashMap<Type, CstType> interns =
new HashMap<Type, CstType>(100);
- /** non-null; instance corresponding to the class <code>Object</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Object} */
public static final CstType OBJECT = intern(Type.OBJECT);
- /** non-null; instance corresponding to the class <code>Boolean</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Boolean} */
public static final CstType BOOLEAN = intern(Type.BOOLEAN_CLASS);
- /** non-null; instance corresponding to the class <code>Byte</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Byte} */
public static final CstType BYTE = intern(Type.BYTE_CLASS);
- /** non-null; instance corresponding to the class <code>Character</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Character} */
public static final CstType CHARACTER = intern(Type.CHARACTER_CLASS);
- /** non-null; instance corresponding to the class <code>Double</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Double} */
public static final CstType DOUBLE = intern(Type.DOUBLE_CLASS);
- /** non-null; instance corresponding to the class <code>Float</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Float} */
public static final CstType FLOAT = intern(Type.FLOAT_CLASS);
- /** non-null; instance corresponding to the class <code>Long</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Long} */
public static final CstType LONG = intern(Type.LONG_CLASS);
- /** non-null; instance corresponding to the class <code>Integer</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Integer} */
public static final CstType INTEGER = intern(Type.INTEGER_CLASS);
- /** non-null; instance corresponding to the class <code>Short</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Short} */
public static final CstType SHORT = intern(Type.SHORT_CLASS);
- /** non-null; instance corresponding to the class <code>Void</code> */
+ /** {@code non-null;} instance corresponding to the class {@code Void} */
public static final CstType VOID = intern(Type.VOID_CLASS);
- /** non-null; instance corresponding to the type <code>boolean[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code boolean[]} */
public static final CstType BOOLEAN_ARRAY = intern(Type.BOOLEAN_ARRAY);
- /** non-null; instance corresponding to the type <code>byte[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code byte[]} */
public static final CstType BYTE_ARRAY = intern(Type.BYTE_ARRAY);
- /** non-null; instance corresponding to the type <code>char[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code char[]} */
public static final CstType CHAR_ARRAY = intern(Type.CHAR_ARRAY);
- /** non-null; instance corresponding to the type <code>double[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code double[]} */
public static final CstType DOUBLE_ARRAY = intern(Type.DOUBLE_ARRAY);
- /** non-null; instance corresponding to the type <code>float[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code float[]} */
public static final CstType FLOAT_ARRAY = intern(Type.FLOAT_ARRAY);
- /** non-null; instance corresponding to the type <code>long[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code long[]} */
public static final CstType LONG_ARRAY = intern(Type.LONG_ARRAY);
- /** non-null; instance corresponding to the type <code>int[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code int[]} */
public static final CstType INT_ARRAY = intern(Type.INT_ARRAY);
- /** non-null; instance corresponding to the type <code>short[]</code> */
+ /** {@code non-null;} instance corresponding to the type {@code short[]} */
public static final CstType SHORT_ARRAY = intern(Type.SHORT_ARRAY);
- /** non-null; the underlying type */
+ /** {@code non-null;} the underlying type */
private final Type type;
/**
- * null-ok; the type descriptor corresponding to this instance, if
+ * {@code null-ok;} the type descriptor corresponding to this instance, if
* calculated
*/
private CstUtf8 descriptor;
@@ -95,10 +95,10 @@
* Returns an instance of this class that represents the wrapper
* class corresponding to a given primitive type. For example, if
* given {@link Type#INT}, this method returns the class reference
- * <code>java.lang.Integer</code>.
+ * {@code java.lang.Integer}.
*
- * @param primitiveType non-null; the primitive type
- * @return non-null; the corresponding wrapper class
+ * @param primitiveType {@code non-null;} the primitive type
+ * @return {@code non-null;} the corresponding wrapper class
*/
public static CstType forBoxedPrimitiveType(Type primitiveType) {
switch (primitiveType.getBasicType()) {
@@ -119,8 +119,8 @@
/**
* Returns an interned instance of this class for the given type.
*
- * @param type non-null; the underlying type
- * @return non-null; an appropriately-constructed instance
+ * @param type {@code non-null;} the underlying type
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static CstType intern(Type type) {
CstType cst = interns.get(type);
@@ -136,7 +136,7 @@
/**
* Constructs an instance.
*
- * @param type non-null; the underlying type
+ * @param type {@code non-null;} the underlying type
*/
public CstType(Type type) {
if (type == null) {
@@ -207,9 +207,9 @@
/**
* Gets the underlying type (as opposed to the type corresponding
* to this instance as a constant, which is always
- * <code>Class</code>).
+ * {@code Class}).
*
- * @return non-null; the type corresponding to the name
+ * @return {@code non-null;} the type corresponding to the name
*/
public Type getClassType() {
return type;
@@ -218,7 +218,7 @@
/**
* Gets the type descriptor for this instance.
*
- * @return non-null; the descriptor
+ * @return {@code non-null;} the descriptor
*/
public CstUtf8 getDescriptor() {
if (descriptor == null) {
diff --git a/dx/src/com/android/dx/rop/cst/CstUtf8.java b/dx/src/com/android/dx/rop/cst/CstUtf8.java
index f0ca5f5..2c7a1df 100644
--- a/dx/src/com/android/dx/rop/cst/CstUtf8.java
+++ b/dx/src/com/android/dx/rop/cst/CstUtf8.java
@@ -20,19 +20,19 @@
import com.android.dx.util.Hex;
/**
- * Constants of type <code>CONSTANT_Utf8_info</code>.
+ * Constants of type {@code CONSTANT_Utf8_info}.
*/
public final class CstUtf8 extends Constant {
/**
- * non-null; instance representing <code>""</code>, that is, the
+ * {@code non-null;} instance representing {@code ""}, that is, the
* empty string
*/
public static final CstUtf8 EMPTY_STRING = new CstUtf8("");
- /** non-null; the UTF-8 value as a string */
+ /** {@code non-null;} the UTF-8 value as a string */
private final String string;
- /** non-null; the UTF-8 value as bytes */
+ /** {@code non-null;} the UTF-8 value as bytes */
private final ByteArray bytes;
/**
@@ -40,8 +40,8 @@
* differs from normal UTF-8 in the handling of character '\0' and
* surrogate pairs.
*
- * @param string non-null; the string to convert
- * @return non-null; the UTF-8 bytes for it
+ * @param string {@code non-null;} the string to convert
+ * @return {@code non-null;} the UTF-8 bytes for it
*/
public static byte[] stringToUtf8Bytes(String string) {
int len = string.length();
@@ -73,8 +73,8 @@
/**
* Converts an array of UTF-8 bytes into a string.
*
- * @param bytes non-null; the bytes to convert
- * @return non-null; the converted string
+ * @param bytes {@code non-null;} the bytes to convert
+ * @return {@code non-null;} the converted string
*/
public static String utf8BytesToString(ByteArray bytes) {
int length = bytes.size();
@@ -173,9 +173,9 @@
}
/**
- * Constructs an instance from a <code>String</code>.
+ * Constructs an instance from a {@code String}.
*
- * @param string non-null; the UTF-8 value as a string
+ * @param string {@code non-null;} the UTF-8 value as a string
*/
public CstUtf8(String string) {
if (string == null) {
@@ -189,7 +189,7 @@
/**
* Constructs an instance from some UTF-8 bytes.
*
- * @param bytes non-null; array of the UTF-8 bytes
+ * @param bytes {@code non-null;} array of the UTF-8 bytes
*/
public CstUtf8(ByteArray bytes) {
if (bytes == null) {
@@ -299,7 +299,7 @@
* Gets the value as a human-oriented string, surrounded by double
* quotes.
*
- * @return non-null; the quoted string
+ * @return {@code non-null;} the quoted string
*/
public String toQuoted() {
return '\"' + toHuman() + '\"';
@@ -310,8 +310,8 @@
* quotes, but ellipsizes the result if it is longer than the given
* maximum length
*
- * @param maxLength >= 5; the maximum length of the string to return
- * @return non-null; the quoted string
+ * @param maxLength {@code >= 5;} the maximum length of the string to return
+ * @return {@code non-null;} the quoted string
*/
public String toQuoted(int maxLength) {
String string = toHuman();
@@ -332,7 +332,7 @@
* Gets the UTF-8 value as a string.
* The returned string is always already interned.
*
- * @return non-null; the UTF-8 value as a string
+ * @return {@code non-null;} the UTF-8 value as a string
*/
public String getString() {
return string;
@@ -341,7 +341,7 @@
/**
* Gets the UTF-8 value as UTF-8 encoded bytes.
*
- * @return non-null; an array of the UTF-8 bytes
+ * @return {@code non-null;} an array of the UTF-8 bytes
*/
public ByteArray getBytes() {
return bytes;
@@ -351,7 +351,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 >= 0; the UTF-8 size
+ * @return {@code >= 0;} the UTF-8 size
*/
public int getUtf8Size() {
return bytes.size();
@@ -360,10 +360,10 @@
/**
* Gets the size of this instance as UTF-16 code points. That is,
* get the number of 16-bit chars in the UTF-16 encoding of this
- * instance. This is the same as the <code>length</code> of the
- * Java <code>String</code> representation of this instance.
+ * instance. This is the same as the {@code length} of the
+ * Java {@code String} representation of this instance.
*
- * @return >= 0; the UTF-16 size
+ * @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 6979102..82c3ab7 100644
--- a/dx/src/com/android/dx/rop/cst/StdConstantPool.java
+++ b/dx/src/com/android/dx/rop/cst/StdConstantPool.java
@@ -26,16 +26,16 @@
*/
public final class StdConstantPool
extends MutabilityControl implements ConstantPool {
- /** non-null; array of entries */
+ /** {@code non-null;} array of entries */
private final Constant[] entries;
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * 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</code>, and is in fact
+ * class file field {@code constant_pool_count}, and is in fact
* always at least one more than the actual size of the constant pool,
- * as element <code>0</code> is always invalid.
+ * as element {@code 0} is always invalid.
*/
public StdConstantPool(int size) {
super(size > 1);
@@ -90,8 +90,8 @@
/**
* Sets the entry at the given index.
*
- * @param n >= 1, < size(); which entry
- * @param cst null-ok; the constant to store
+ * @param n {@code >= 1, < size();} which entry
+ * @param cst {@code null-ok;} the constant to store
*/
public void set(int n, Constant cst) {
throwIfImmutable();
diff --git a/dx/src/com/android/dx/rop/cst/TypedConstant.java b/dx/src/com/android/dx/rop/cst/TypedConstant.java
index 54472b0..823d9c4 100644
--- a/dx/src/com/android/dx/rop/cst/TypedConstant.java
+++ b/dx/src/com/android/dx/rop/cst/TypedConstant.java
@@ -26,7 +26,7 @@
/**
* {@inheritDoc}
*
- * This implentation always returns <code>this</code>.
+ * This implentation always returns {@code this}.
*/
public final TypeBearer getFrameType() {
return this;
diff --git a/dx/src/com/android/dx/rop/cst/Zeroes.java b/dx/src/com/android/dx/rop/cst/Zeroes.java
index 3379b6c..8bed657 100644
--- a/dx/src/com/android/dx/rop/cst/Zeroes.java
+++ b/dx/src/com/android/dx/rop/cst/Zeroes.java
@@ -30,10 +30,10 @@
}
/**
- * Gets the "zero" (or <code>null</code>) value for the given type.
+ * Gets the "zero" (or {@code null}) value for the given type.
*
- * @param type non-null; the type in question
- * @return non-null; its "zero" value
+ * @param type {@code non-null;} the type in question
+ * @return {@code non-null;} its "zero" value
*/
public static Constant zeroFor(Type type) {
switch (type.getBasicType()) {
diff --git a/dx/src/com/android/dx/rop/package-info.java b/dx/src/com/android/dx/rop/package-info.java
index 97fe9de..aaf21ee 100644
--- a/dx/src/com/android/dx/rop/package-info.java
+++ b/dx/src/com/android/dx/rop/package-info.java
@@ -19,7 +19,7 @@
/**
* <h1>An Introduction to Rop Form</h1>
*
- * This package contains classes associated with dx's <code>Rop</code>
+ * This package contains classes associated with dx's {@code Rop}
* intermediate form.<p>
*
* The Rop form is intended to represent the instructions and the control-flow
@@ -33,16 +33,16 @@
* <li> {@link BasicBlock} and its per-method container, {@link BasicBlockList},
* the representation of control flow elements.
* <li> {@link Insn} and its subclasses along with its per-basic block
- * container {@link InsnList}. <code>Insn</code> instances represent
+ * container {@link InsnList}. {@code Insn} instances represent
* individual instructions in the abstract register machine.
* <li> {@link RegisterSpec} and its container {@link RegisterSpecList}. A
* register spec encodes register number, register width, type information,
* and potentially local variable information as well for instruction sources
* and results.
* <li> {@link Rop} instances represent opcodes in the abstract machine. Many
- * <code>Rop</code> instances are singletons defined in static fields in
+ * {@code Rop} instances are singletons defined in static fields in
* {@link Rops}. The rest are constructed dynamically using static methods
- * in <code>Rops</code>
+ * in {@code Rops}
* <li> {@link RegOps} lists numeric constants for the opcodes
* <li> {@link Constant} and its subclasses represent constant data values
* that opcodes may refer to.
@@ -62,8 +62,8 @@
* bytecode. Blocks that don't originate directly from source bytecode have
* labels generated for them in a mostly arbitrary order.<p>
*
- * Blocks are referred to by their label, for the most part, because <code>
- * BasicBlock</code> instances are immutable and thus any modification to
+ * Blocks are referred to by their label, for the most part, because
+ * {@code BasicBlock} instances are immutable and thus any modification to
* the control flow graph or the instruction list results in replacement
* instances (with identical labels) being created.<p>
*
@@ -105,7 +105,7 @@
* instruction where a catch block exists inside the current method for that
* exception class. Since the only possible path is the exception path, only
* the exception path (which cannot be a primary successor) is a successor.
- * An example of this is shown in <code>dx/tests/092-ssa-cfg-edge-cases</code>.
+ * An example of this is shown in {@code dx/tests/092-ssa-cfg-edge-cases}.
*
* <h2>Rop Instructions</h2>
*
@@ -123,18 +123,18 @@
* Rops#MOVE_RESULT move-result} or {@link Rops#MOVE_RESULT_PSEUDO
* move-result-pseudo} instructions at the top of the primary successor block.
*
- * Only a single <code>move-result</code> or <code>move-result-pseudo</code>
+ * Only a single {@code move-result} or {@code move-result-pseudo}
* may exist in any block and it must be exactly the first instruction in the
* block.
*
- * A <code>move-result</code> instruction is used for the results of call-like
- * instructions. If the value produced by a <code>move-result</code> is not
+ * A {@code move-result} instruction is used for the results of call-like
+ * instructions. If the value produced by a {@code move-result} is not
* used by the method, it may be eliminated as dead code.
*
- * A <code>move-result-pseudo</code> instruction is used for the results of
+ * A {@code move-result-pseudo} instruction is used for the results of
* non-call-like throwing instructions. It may never be considered dead code
* since the final dex instruction will always indicate a result register.
- * If a required <code>move-result-pseudo</code> instruction is not found
+ * If a required {@code move-result-pseudo} instruction is not found
* during conversion to dex bytecode, an exception will be thrown.
*
* <h3>move-exception</h3>
@@ -148,25 +148,25 @@
* <h3>move-param</h3>
*
* A {@link RegOps.MOVE_PARAM move-param} instruction represents a method
- * parameter. Every <code>move-param</code> instruction is a
+ * parameter. Every {@code move-param} instruction is a
* {@link PlainCstInsn}. The index of the method parameter they refer to is
* carried as the {@link CstInteger integer constant} associated with the
* instruction.
*
- * Any number of <code>move-param</code> instructions referring to the same
+ * Any number of {@code move-param} instructions referring to the same
* parameter index may be included in a method's instruction lists. They
* have no restrictions on placement beyond those of any other
* {@link Rop.BRANCH_NONE} instruction. Note that the SSA optimizer arranges the
* parameter assignments to align with the dex bytecode calling conventions.
* With parameter assignments so arranged, the
- * {@link com.android.dx.dex.code.RopTranslator} sees Rop <code>move-param</code>
+ * {@link com.android.dx.dex.code.RopTranslator} sees Rop {@code move-param}
* instructions as unnecessary in dex form and eliminates them.
*
* <h3>mark-local</h3>
*
* A {@link RegOps.MARK_LOCAL mark-local} instruction indicates that a local
* variable becomes live in a specified register specified register for the
- * purposes of debug information. A <code>mark-local</code> instruction has
+ * purposes of debug information. A {@code mark-local} instruction has
* a single source (the register which will now be considered a local variable)
* and no results. The instruction has no side effect.<p>
*
@@ -179,23 +179,22 @@
* an assignment occurring. A common example of this is occurs in the Rop
* representation of the following code:<p>
*
- * <code>
+ * <pre>
* try {
* Object foo = null;
* foo = new Object();
- * } catch (Throwable ex) {
- * }
- * </code>
+ * } catch (Throwable ex) { }
+ * </pre>
*
- * An object's initialization occurs in two steps. First, a <code>new-instance
- * </code> instruction is executed, whose result is stored in a register.
- * However, that register can not yet be considered to contain "foo". That's
- * because the instance's constructor method must be called via an
- * <code>invoke</code> instruction. The constructor method, however, may
+ * An object's initialization occurs in two steps. First, a
+ * {@code new-instance} instruction is executed, whose result is stored in a
+ * register. However, that register can not yet be considered to contain
+ * "foo". That's because the instance's constructor method must be called
+ * via an {@code invoke} instruction. The constructor method, however, may
* throw an exception. And if an exception occurs, then "foo" should remain
- * null. So "foo" becomes the value of the result of the <code>new-instance
- * </code> instruction after the (void) constructor method is invoked and
- * returns successfully. In such a case, a <code>mark-local</code> will
+ * null. So "foo" becomes the value of the result of the {@code new-instance}
+ * instruction after the (void) constructor method is invoked and
+ * returns successfully. In such a case, a {@code mark-local} will
* typically occur at the beginning of the primary successor block following
* the invocation to the constructor.
*/
diff --git a/dx/src/com/android/dx/rop/type/Prototype.java b/dx/src/com/android/dx/rop/type/Prototype.java
index a6ee742..7e6ab59 100644
--- a/dx/src/com/android/dx/rop/type/Prototype.java
+++ b/dx/src/com/android/dx/rop/type/Prototype.java
@@ -21,23 +21,23 @@
/**
* Representation of a method decriptor. Instances of this class are
* generally interned and may be usefully compared with each other
- * using <code>==</code>.
+ * using {@code ==}.
*/
public final class Prototype implements Comparable<Prototype> {
- /** non-null; intern table mapping string descriptors to instances */
+ /** {@code non-null;} intern table mapping string descriptors to instances */
private static final HashMap<String, Prototype> internTable =
new HashMap<String, Prototype>(500);
- /** non-null; method descriptor */
+ /** {@code non-null;} method descriptor */
private final String descriptor;
- /** non-null; return type */
+ /** {@code non-null;} return type */
private final Type returnType;
- /** non-null; list of parameter types */
+ /** {@code non-null;} list of parameter types */
private final StdTypeList parameterTypes;
- /** null-ok; list of parameter frame types, if calculated */
+ /** {@code null-ok;} list of parameter frame types, if calculated */
private StdTypeList parameterFrameTypes;
/**
@@ -45,8 +45,8 @@
* given method descriptor. See vmspec-2 sec4.3.3 for details on the
* field descriptor syntax.
*
- * @param descriptor non-null; the descriptor
- * @return non-null; the corresponding instance
+ * @param descriptor {@code non-null;} the descriptor
+ * @return {@code non-null;} the corresponding instance
* @throws IllegalArgumentException thrown if the descriptor has
* invalid syntax
*/
@@ -111,8 +111,8 @@
* that there is a '(' at the start of the descriptor and a
* single ')' somewhere before the end.
*
- * @param descriptor non-null; the descriptor string
- * @return non-null; array large enough to hold all parsed parameter
+ * @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
*/
private static Type[] makeParameterArray(String descriptor) {
@@ -153,14 +153,14 @@
/**
* Interns an instance, adding to the descriptor as necessary based
* on the given definer, name, and flags. For example, an init
- * method has an uninitialized object of type <code>definer</code>
+ * method has an uninitialized object of type {@code definer}
* as its first argument.
*
- * @param descriptor non-null; the descriptor string
- * @param definer non-null; class the method is defined on
+ * @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
* @param isInit whether this is an init method
- * @return non-null; the interned instance
+ * @return {@code non-null;} the interned instance
*/
public static Prototype intern(String descriptor, Type definer,
boolean isStatic, boolean isInit) {
@@ -179,11 +179,11 @@
/**
* Interns an instance which consists of the given number of
- * <code>int</code>s along with the given return type
+ * {@code int}s along with the given return type
*
- * @param returnType non-null; the return type
- * @param count > 0; the number of elements in the prototype
- * @return non-null; the interned instance
+ * @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
*/
public static Prototype internInts(Type returnType, int count) {
// Make the descriptor...
@@ -207,7 +207,7 @@
* Constructs an instance. This is a private constructor; use one
* of the public static methods to get instances.
*
- * @param descriptor non-null; the descriptor string
+ * @param descriptor {@code non-null;} the descriptor string
*/
private Prototype(String descriptor, Type returnType,
StdTypeList parameterTypes) {
@@ -304,7 +304,7 @@
/**
* Gets the descriptor string.
*
- * @return non-null; the descriptor
+ * @return {@code non-null;} the descriptor
*/
public String getDescriptor() {
return descriptor;
@@ -313,7 +313,7 @@
/**
* Gets the return type.
*
- * @return non-null; the return type
+ * @return {@code non-null;} the return type
*/
public Type getReturnType() {
return returnType;
@@ -322,7 +322,7 @@
/**
* Gets the list of parameter types.
*
- * @return non-null; the list of parameter types
+ * @return {@code non-null;} the list of parameter types
*/
public StdTypeList getParameterTypes() {
return parameterTypes;
@@ -334,7 +334,7 @@
* "intlike" types (see {@link Type#isIntlike}) are replaced by
* {@link Type#INT}.
*
- * @return non-null; the list of parameter frame types
+ * @return {@code non-null;} the list of parameter frame types
*/
public StdTypeList getParameterFrameTypes() {
if (parameterFrameTypes == null) {
@@ -360,8 +360,8 @@
* except that it has an additional parameter prepended to the original's
* argument list.
*
- * @param param non-null; the new first parameter
- * @return non-null; an appropriately-constructed instance
+ * @param param {@code non-null;} the new first parameter
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public Prototype withFirstParameter(Type param) {
String newDesc = "(" + param.getDescriptor() + descriptor.substring(1);
@@ -380,8 +380,8 @@
* there. If a conflicting value is already in the table, then leave it.
* Return the interned value.
*
- * @param desc non-null; instance to make interned
- * @return non-null; the actual interned object
+ * @param desc {@code non-null;} instance to make interned
+ * @return {@code non-null;} the actual interned object
*/
private static Prototype putIntern(Prototype desc) {
synchronized (internTable) {
diff --git a/dx/src/com/android/dx/rop/type/StdTypeList.java b/dx/src/com/android/dx/rop/type/StdTypeList.java
index a4c2d44..a023812 100644
--- a/dx/src/com/android/dx/rop/type/StdTypeList.java
+++ b/dx/src/com/android/dx/rop/type/StdTypeList.java
@@ -23,149 +23,149 @@
*/
public final class StdTypeList
extends FixedSizeList implements TypeList {
- /** non-null; no-element instance */
+ /** {@code non-null;} no-element instance */
public static final StdTypeList EMPTY = new StdTypeList(0);
- /** non-null; the list <code>[int]</code> */
+ /** {@code non-null;} the list {@code [int]} */
public static final StdTypeList INT = StdTypeList.make(Type.INT);
- /** non-null; the list <code>[long]</code> */
+ /** {@code non-null;} the list {@code [long]} */
public static final StdTypeList LONG = StdTypeList.make(Type.LONG);
- /** non-null; the list <code>[float]</code> */
+ /** {@code non-null;} the list {@code [float]} */
public static final StdTypeList FLOAT = StdTypeList.make(Type.FLOAT);
- /** non-null; the list <code>[double]</code> */
+ /** {@code non-null;} the list {@code [double]} */
public static final StdTypeList DOUBLE = StdTypeList.make(Type.DOUBLE);
- /** non-null; the list <code>[Object]</code> */
+ /** {@code non-null;} the list {@code [Object]} */
public static final StdTypeList OBJECT = StdTypeList.make(Type.OBJECT);
- /** non-null; the list <code>[ReturnAddress]</code> */
+ /** {@code non-null;} the list {@code [ReturnAddress]} */
public static final StdTypeList RETURN_ADDRESS
= StdTypeList.make(Type.RETURN_ADDRESS);
- /** non-null; the list <code>[Throwable]</code> */
+ /** {@code non-null;} the list {@code [Throwable]} */
public static final StdTypeList THROWABLE =
StdTypeList.make(Type.THROWABLE);
- /** non-null; the list <code>[int, int]</code> */
+ /** {@code non-null;} the list {@code [int, int]} */
public static final StdTypeList INT_INT =
StdTypeList.make(Type.INT, Type.INT);
- /** non-null; the list <code>[long, long]</code> */
+ /** {@code non-null;} the list {@code [long, long]} */
public static final StdTypeList LONG_LONG =
StdTypeList.make(Type.LONG, Type.LONG);
- /** non-null; the list <code>[float, float]</code> */
+ /** {@code non-null;} the list {@code [float, float]} */
public static final StdTypeList FLOAT_FLOAT =
StdTypeList.make(Type.FLOAT, Type.FLOAT);
- /** non-null; the list <code>[double, double]</code> */
+ /** {@code non-null;} the list {@code [double, double]} */
public static final StdTypeList DOUBLE_DOUBLE =
StdTypeList.make(Type.DOUBLE, Type.DOUBLE);
- /** non-null; the list <code>[Object, Object]</code> */
+ /** {@code non-null;} the list {@code [Object, Object]} */
public static final StdTypeList OBJECT_OBJECT =
StdTypeList.make(Type.OBJECT, Type.OBJECT);
- /** non-null; the list <code>[int, Object]</code> */
+ /** {@code non-null;} the list {@code [int, Object]} */
public static final StdTypeList INT_OBJECT =
StdTypeList.make(Type.INT, Type.OBJECT);
- /** non-null; the list <code>[long, Object]</code> */
+ /** {@code non-null;} the list {@code [long, Object]} */
public static final StdTypeList LONG_OBJECT =
StdTypeList.make(Type.LONG, Type.OBJECT);
- /** non-null; the list <code>[float, Object]</code> */
+ /** {@code non-null;} the list {@code [float, Object]} */
public static final StdTypeList FLOAT_OBJECT =
StdTypeList.make(Type.FLOAT, Type.OBJECT);
- /** non-null; the list <code>[double, Object]</code> */
+ /** {@code non-null;} the list {@code [double, Object]} */
public static final StdTypeList DOUBLE_OBJECT =
StdTypeList.make(Type.DOUBLE, Type.OBJECT);
- /** non-null; the list <code>[long, int]</code> */
+ /** {@code non-null;} the list {@code [long, int]} */
public static final StdTypeList LONG_INT =
StdTypeList.make(Type.LONG, Type.INT);
- /** non-null; the list <code>[int[], int]</code> */
+ /** {@code non-null;} the list {@code [int[], int]} */
public static final StdTypeList INTARR_INT =
StdTypeList.make(Type.INT_ARRAY, Type.INT);
- /** non-null; the list <code>[long[], int]</code> */
+ /** {@code non-null;} the list {@code [long[], int]} */
public static final StdTypeList LONGARR_INT =
StdTypeList.make(Type.LONG_ARRAY, Type.INT);
- /** non-null; the list <code>[float[], int]</code> */
+ /** {@code non-null;} the list {@code [float[], int]} */
public static final StdTypeList FLOATARR_INT =
StdTypeList.make(Type.FLOAT_ARRAY, Type.INT);
- /** non-null; the list <code>[double[], int]</code> */
+ /** {@code non-null;} the list {@code [double[], int]} */
public static final StdTypeList DOUBLEARR_INT =
StdTypeList.make(Type.DOUBLE_ARRAY, Type.INT);
- /** non-null; the list <code>[Object[], int]</code> */
+ /** {@code non-null;} the list {@code [Object[], int]} */
public static final StdTypeList OBJECTARR_INT =
StdTypeList.make(Type.OBJECT_ARRAY, Type.INT);
- /** non-null; the list <code>[boolean[], int]</code> */
+ /** {@code non-null;} the list {@code [boolean[], int]} */
public static final StdTypeList BOOLEANARR_INT =
StdTypeList.make(Type.BOOLEAN_ARRAY, Type.INT);
- /** non-null; the list <code>[byte[], int]</code> */
+ /** {@code non-null;} the list {@code [byte[], int]} */
public static final StdTypeList BYTEARR_INT =
StdTypeList.make(Type.BYTE_ARRAY, Type.INT);
- /** non-null; the list <code>[char[], int]</code> */
+ /** {@code non-null;} the list {@code [char[], int]} */
public static final StdTypeList CHARARR_INT =
StdTypeList.make(Type.CHAR_ARRAY, Type.INT);
- /** non-null; the list <code>[short[], int]</code> */
+ /** {@code non-null;} the list {@code [short[], int]} */
public static final StdTypeList SHORTARR_INT =
StdTypeList.make(Type.SHORT_ARRAY, Type.INT);
- /** non-null; the list <code>[int, int[], int]</code> */
+ /** {@code non-null;} the list {@code [int, int[], int]} */
public static final StdTypeList INT_INTARR_INT =
StdTypeList.make(Type.INT, Type.INT_ARRAY, Type.INT);
- /** non-null; the list <code>[long, long[], int]</code> */
+ /** {@code non-null;} the list {@code [long, long[], int]} */
public static final StdTypeList LONG_LONGARR_INT =
StdTypeList.make(Type.LONG, Type.LONG_ARRAY, Type.INT);
- /** non-null; the list <code>[float, float[], int]</code> */
+ /** {@code non-null;} the list {@code [float, float[], int]} */
public static final StdTypeList FLOAT_FLOATARR_INT =
StdTypeList.make(Type.FLOAT, Type.FLOAT_ARRAY, Type.INT);
- /** non-null; the list <code>[double, double[], int]</code> */
+ /** {@code non-null;} the list {@code [double, double[], int]} */
public static final StdTypeList DOUBLE_DOUBLEARR_INT =
StdTypeList.make(Type.DOUBLE, Type.DOUBLE_ARRAY, Type.INT);
- /** non-null; the list <code>[Object, Object[], int]</code> */
+ /** {@code non-null;} the list {@code [Object, Object[], int]} */
public static final StdTypeList OBJECT_OBJECTARR_INT =
StdTypeList.make(Type.OBJECT, Type.OBJECT_ARRAY, Type.INT);
- /** non-null; the list <code>[int, boolean[], int]</code> */
+ /** {@code non-null;} the list {@code [int, boolean[], int]} */
public static final StdTypeList INT_BOOLEANARR_INT =
StdTypeList.make(Type.INT, Type.BOOLEAN_ARRAY, Type.INT);
- /** non-null; the list <code>[int, byte[], int]</code> */
+ /** {@code non-null;} the list {@code [int, byte[], int]} */
public static final StdTypeList INT_BYTEARR_INT =
StdTypeList.make(Type.INT, Type.BYTE_ARRAY, Type.INT);
- /** non-null; the list <code>[int, char[], int]</code> */
+ /** {@code non-null;} the list {@code [int, char[], int]} */
public static final StdTypeList INT_CHARARR_INT =
StdTypeList.make(Type.INT, Type.CHAR_ARRAY, Type.INT);
- /** non-null; the list <code>[int, short[], int]</code> */
+ /** {@code non-null;} the list {@code [int, short[], int]} */
public static final StdTypeList INT_SHORTARR_INT =
StdTypeList.make(Type.INT, Type.SHORT_ARRAY, Type.INT);
/**
* Makes a single-element instance.
*
- * @param type non-null; the element
- * @return non-null; an appropriately-constructed instance
+ * @param type {@code non-null;} the element
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static StdTypeList make(Type type) {
StdTypeList result = new StdTypeList(1);
@@ -176,9 +176,9 @@
/**
* Makes a two-element instance.
*
- * @param type0 non-null; the first element
- * @param type1 non-null; the second element
- * @return non-null; an appropriately-constructed 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
*/
public static StdTypeList make(Type type0, Type type1) {
StdTypeList result = new StdTypeList(2);
@@ -190,10 +190,10 @@
/**
* Makes a three-element instance.
*
- * @param type0 non-null; the first element
- * @param type1 non-null; the second element
- * @param type2 non-null; the third element
- * @return non-null; an appropriately-constructed 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
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static StdTypeList make(Type type0, Type type1, Type type2) {
StdTypeList result = new StdTypeList(3);
@@ -206,11 +206,11 @@
/**
* Makes a four-element instance.
*
- * @param type0 non-null; the first element
- * @param type1 non-null; the second element
- * @param type2 non-null; the third element
- * @param type3 non-null; the fourth element
- * @return non-null; an appropriately-constructed 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
+ * @param type3 {@code non-null;} the fourth element
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static StdTypeList make(Type type0, Type type1, Type type2,
Type type3) {
@@ -227,8 +227,8 @@
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
*
- * @param list non-null; the list to convert
- * @return non-null; the human form
+ * @param list {@code non-null;} the list to convert
+ * @return {@code non-null;} the human form
*/
public static String toHuman(TypeList list) {
int size = list.size();
@@ -254,8 +254,8 @@
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
*
- * @param list non-null; the list to inspect
- * @return non-null; the hash code
+ * @param list {@code non-null;} the list to inspect
+ * @return {@code non-null;} the hash code
*/
public static int hashContents(TypeList list) {
int size = list.size();
@@ -273,8 +273,8 @@
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
*
- * @param list1 non-null; one list to compare
- * @param list2 non-null; another list to compare
+ * @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
*/
public static boolean equalContents(TypeList list1, TypeList list2) {
@@ -298,8 +298,8 @@
* is a static method so as to work on arbitrary {@link TypeList}
* instances.
*
- * @param list1 non-null; one list to compare
- * @param list2 non-null; another list to compare
+ * @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
*/
public static int compareContents(TypeList list1, TypeList list2) {
@@ -324,7 +324,7 @@
}
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -366,10 +366,10 @@
/**
* 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</code>.
+ * will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which element
- * @return non-null; the indicated element
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
*/
public Type get(int n) {
return (Type) get0(n);
@@ -378,8 +378,8 @@
/**
* Sets the type at the given index.
*
- * @param n >= 0, < size(); which element
- * @param type non-null; the type to store
+ * @param n {@code >= 0, < size();} which element
+ * @param type {@code non-null;} the type to store
*/
public void set(int n, Type type) {
set0(n, type);
@@ -390,8 +390,8 @@
* except that it has an additional type prepended to the
* original.
*
- * @param type non-null; the new first element
- * @return non-null; an appropriately-constructed instance
+ * @param type {@code non-null;} the new first element
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public StdTypeList withFirst(Type type) {
int sz = size();
diff --git a/dx/src/com/android/dx/rop/type/Type.java b/dx/src/com/android/dx/rop/type/Type.java
index 09ea2e2..64c3c30 100644
--- a/dx/src/com/android/dx/rop/type/Type.java
+++ b/dx/src/com/android/dx/rop/type/Type.java
@@ -24,41 +24,41 @@
* Representation of a value type, such as may appear in a field, in a
* local, on a stack, or in a method descriptor. Instances of this
* class are generally interned and may be usefully compared with each
- * other using <code>==</code>.
+ * other using {@code ==}.
*/
public final class Type implements TypeBearer, Comparable<Type> {
- /** non-null; intern table mapping string descriptors to instances */
+ /** {@code non-null;} intern table mapping string descriptors to instances */
private static final HashMap<String, Type> internTable =
new HashMap<String, Type>(500);
- /** basic type constant for <code>void</code> */
+ /** basic type constant for {@code void} */
public static final int BT_VOID = 0;
- /** basic type constant for <code>boolean</code> */
+ /** basic type constant for {@code boolean} */
public static final int BT_BOOLEAN = 1;
- /** basic type constant for <code>byte</code> */
+ /** basic type constant for {@code byte} */
public static final int BT_BYTE = 2;
- /** basic type constant for <code>char</code> */
+ /** basic type constant for {@code char} */
public static final int BT_CHAR = 3;
- /** basic type constant for <code>double</code> */
+ /** basic type constant for {@code double} */
public static final int BT_DOUBLE = 4;
- /** basic type constant for <code>float</code> */
+ /** basic type constant for {@code float} */
public static final int BT_FLOAT = 5;
- /** basic type constant for <code>int</code> */
+ /** basic type constant for {@code int} */
public static final int BT_INT = 6;
- /** basic type constant for <code>long</code> */
+ /** basic type constant for {@code long} */
public static final int BT_LONG = 7;
- /** basic type constant for <code>short</code> */
+ /** basic type constant for {@code short} */
public static final int BT_SHORT = 8;
- /** basic type constant for <code>Object</code> */
+ /** basic type constant for {@code Object} */
public static final int BT_OBJECT = 9;
/** basic type constant for a return address */
@@ -67,37 +67,37 @@
/** count of basic type constants */
public static final int BT_COUNT = 11;
- /** non-null; instance representing <code>boolean</code> */
+ /** {@code non-null;} instance representing {@code boolean} */
public static final Type BOOLEAN = new Type("Z", BT_BOOLEAN);
- /** non-null; instance representing <code>byte</code> */
+ /** {@code non-null;} instance representing {@code byte} */
public static final Type BYTE = new Type("B", BT_BYTE);
- /** non-null; instance representing <code>char</code> */
+ /** {@code non-null;} instance representing {@code char} */
public static final Type CHAR = new Type("C", BT_CHAR);
- /** non-null; instance representing <code>double</code> */
+ /** {@code non-null;} instance representing {@code double} */
public static final Type DOUBLE = new Type("D", BT_DOUBLE);
- /** non-null; instance representing <code>float</code> */
+ /** {@code non-null;} instance representing {@code float} */
public static final Type FLOAT = new Type("F", BT_FLOAT);
- /** non-null; instance representing <code>int</code> */
+ /** {@code non-null;} instance representing {@code int} */
public static final Type INT = new Type("I", BT_INT);
- /** non-null; instance representing <code>long</code> */
+ /** {@code non-null;} instance representing {@code long} */
public static final Type LONG = new Type("J", BT_LONG);
- /** non-null; instance representing <code>short</code> */
+ /** {@code non-null;} instance representing {@code short} */
public static final Type SHORT = new Type("S", BT_SHORT);
- /** non-null; instance representing <code>void</code> */
+ /** {@code non-null;} instance representing {@code void} */
public static final Type VOID = new Type("V", BT_VOID);
- /** non-null; instance representing a known-<code>null</code> */
+ /** {@code non-null;} instance representing a known-{@code null} */
public static final Type KNOWN_NULL = new Type("<null>", BT_OBJECT);
- /** non-null; instance representing a subroutine return address */
+ /** {@code non-null;} instance representing a subroutine return address */
public static final Type RETURN_ADDRESS = new Type("<addr>", BT_ADDR);
static {
@@ -120,158 +120,158 @@
}
/**
- * non-null; instance representing
- * <code>java.lang.annotation.Annotation</code>
+ * {@code non-null;} instance representing
+ * {@code java.lang.annotation.Annotation}
*/
public static final Type ANNOTATION =
intern("Ljava/lang/annotation/Annotation;");
- /** non-null; instance representing <code>java.lang.Class</code> */
+ /** {@code non-null;} instance representing {@code java.lang.Class} */
public static final Type CLASS = intern("Ljava/lang/Class;");
- /** non-null; instance representing <code>java.lang.Cloneable</code> */
+ /** {@code non-null;} instance representing {@code java.lang.Cloneable} */
public static final Type CLONEABLE = intern("Ljava/lang/Cloneable;");
- /** non-null; instance representing <code>java.lang.Object</code> */
+ /** {@code non-null;} instance representing {@code java.lang.Object} */
public static final Type OBJECT = intern("Ljava/lang/Object;");
- /** non-null; instance representing <code>java.io.Serializable</code> */
+ /** {@code non-null;} instance representing {@code java.io.Serializable} */
public static final Type SERIALIZABLE = intern("Ljava/io/Serializable;");
- /** non-null; instance representing <code>java.lang.String</code> */
+ /** {@code non-null;} instance representing {@code java.lang.String} */
public static final Type STRING = intern("Ljava/lang/String;");
- /** non-null; instance representing <code>java.lang.Throwable</code> */
+ /** {@code non-null;} instance representing {@code java.lang.Throwable} */
public static final Type THROWABLE = intern("Ljava/lang/Throwable;");
/**
- * non-null; instance representing <code>java.lang.Boolean</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Boolean}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type BOOLEAN_CLASS = intern("Ljava/lang/Boolean;");
/**
- * non-null; instance representing <code>java.lang.Byte</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Byte}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type BYTE_CLASS = intern("Ljava/lang/Byte;");
/**
- * non-null; instance representing <code>java.lang.Character</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Character}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type CHARACTER_CLASS = intern("Ljava/lang/Character;");
/**
- * non-null; instance representing <code>java.lang.Double</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Double}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type DOUBLE_CLASS = intern("Ljava/lang/Double;");
/**
- * non-null; instance representing <code>java.lang.Float</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Float}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type FLOAT_CLASS = intern("Ljava/lang/Float;");
/**
- * non-null; instance representing <code>java.lang.Integer</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Integer}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type INTEGER_CLASS = intern("Ljava/lang/Integer;");
/**
- * non-null; instance representing <code>java.lang.Long</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Long}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type LONG_CLASS = intern("Ljava/lang/Long;");
/**
- * non-null; instance representing <code>java.lang.Short</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Short}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type SHORT_CLASS = intern("Ljava/lang/Short;");
/**
- * non-null; instance representing <code>java.lang.Void</code>; the
+ * {@code non-null;} instance representing {@code java.lang.Void}; the
* suffix on the name helps disambiguate this from the instance
* representing a primitive type
*/
public static final Type VOID_CLASS = intern("Ljava/lang/Void;");
- /** non-null; instance representing <code>boolean[]</code> */
+ /** {@code non-null;} instance representing {@code boolean[]} */
public static final Type BOOLEAN_ARRAY = BOOLEAN.getArrayType();
- /** non-null; instance representing <code>byte[]</code> */
+ /** {@code non-null;} instance representing {@code byte[]} */
public static final Type BYTE_ARRAY = BYTE.getArrayType();
- /** non-null; instance representing <code>char[]</code> */
+ /** {@code non-null;} instance representing {@code char[]} */
public static final Type CHAR_ARRAY = CHAR.getArrayType();
- /** non-null; instance representing <code>double[]</code> */
+ /** {@code non-null;} instance representing {@code double[]} */
public static final Type DOUBLE_ARRAY = DOUBLE.getArrayType();
- /** non-null; instance representing <code>float[]</code> */
+ /** {@code non-null;} instance representing {@code float[]} */
public static final Type FLOAT_ARRAY = FLOAT.getArrayType();
- /** non-null; instance representing <code>int[]</code> */
+ /** {@code non-null;} instance representing {@code int[]} */
public static final Type INT_ARRAY = INT.getArrayType();
- /** non-null; instance representing <code>long[]</code> */
+ /** {@code non-null;} instance representing {@code long[]} */
public static final Type LONG_ARRAY = LONG.getArrayType();
- /** non-null; instance representing <code>Object[]</code> */
+ /** {@code non-null;} instance representing {@code Object[]} */
public static final Type OBJECT_ARRAY = OBJECT.getArrayType();
- /** non-null; instance representing <code>short[]</code> */
+ /** {@code non-null;} instance representing {@code short[]} */
public static final Type SHORT_ARRAY = SHORT.getArrayType();
- /** non-null; field descriptor for the type */
+ /** {@code non-null;} field descriptor for the type */
private final String descriptor;
/**
* basic type corresponding to this type; one of the
- * <code>BT_*</code> constants
+ * {@code BT_*} constants
*/
private final int basicType;
/**
- * >= -1; for an uninitialized type, bytecode index that this
- * instance was allocated at; <code>Integer.MAX_VALUE</code> if it
- * was an incoming uninitialized instance; <code>-1</code> if this
+ * {@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
*/
private final int newAt;
/**
- * null-ok; the internal-form class name corresponding to this type, if
- * calculated; only valid if <code>this</code> is a reference type and
+ * {@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
*/
private String className;
/**
- * null-ok; the type corresponding to an array of this type, if
+ * {@code null-ok;} the type corresponding to an array of this type, if
* calculated
*/
private Type arrayType;
/**
- * null-ok; the type corresponding to elements of this type, if
- * calculated; only valid if <code>this</code> is an array type
+ * {@code null-ok;} the type corresponding to elements of this type, if
+ * calculated; only valid if {@code this} is an array type
*/
private Type componentType;
/**
- * null-ok; the type corresponding to the initialized version of
+ * {@code null-ok;} the type corresponding to the initialized version of
* this type, if this instance is in fact an uninitialized type
*/
private Type initializedType;
@@ -280,11 +280,11 @@
* Returns the unique instance corresponding to the type with the
* given descriptor. See vmspec-2 sec4.3.2 for details on the
* field descriptor syntax. This method does <i>not</i> allow
- * <code>"V"</code> (that is, type <code>void</code>) as a valid
+ * {@code "V"} (that is, type {@code void}) as a valid
* descriptor.
*
- * @param descriptor non-null; the descriptor
- * @return non-null; the corresponding instance
+ * @param descriptor {@code non-null;} the descriptor
+ * @return {@code non-null;} the corresponding instance
* @throws IllegalArgumentException thrown if the descriptor has
* invalid syntax
*/
@@ -362,12 +362,12 @@
/**
* Returns the unique instance corresponding to the type with the
- * given descriptor, allowing <code>"V"</code> to return the type
- * for <code>void</code>. Other than that one caveat, this method
+ * 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 non-null; the descriptor
- * @return non-null; the corresponding instance
+ * @param descriptor {@code non-null;} the descriptor
+ * @return {@code non-null;} the corresponding instance
* @throws IllegalArgumentException thrown if the descriptor has
* invalid syntax
*/
@@ -388,12 +388,12 @@
/**
* Returns the unique instance corresponding to the type of the
* class with the given name. Calling this method is equivalent to
- * calling <code>intern(name)</code> if <code>name</code> begins
- * with <code>"["</code> and calling <code>intern("L" + name + ";")</code>
+ * calling {@code intern(name)} if {@code name} begins
+ * with {@code "["} and calling {@code intern("L" + name + ";")}
* in all other cases.
*
- * @param name non-null; the name of the class whose type is desired
- * @return non-null; the corresponding type
+ * @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
* invalid syntax
*/
@@ -414,10 +414,10 @@
* This is a private constructor; use one of the public static
* methods to get instances.
*
- * @param descriptor non-null; the field descriptor for the type
+ * @param descriptor {@code non-null;} the field descriptor for the type
* @param basicType basic type corresponding to this type; one of the
- * <code>BT_*</code> constants
- * @param newAt >= -1 allocation bytecode index
+ * {@code BT_*} constants
+ * @param newAt {@code >= -1;} allocation bytecode index
*/
private Type(String descriptor, int basicType, int newAt) {
if (descriptor == null) {
@@ -445,9 +445,9 @@
* This is a private constructor; use one of the public static
* methods to get instances.
*
- * @param descriptor non-null; the field descriptor for the type
+ * @param descriptor {@code non-null;} the field descriptor for the type
* @param basicType basic type corresponding to this type; one of the
- * <code>BT_*</code> constants
+ * {@code BT_*} constants
*/
private Type(String descriptor, int basicType) {
this(descriptor, basicType, -1);
@@ -560,7 +560,7 @@
/**
* Gets the descriptor.
*
- * @return non-null; the descriptor
+ * @return {@code non-null;} the descriptor
*/
public String getDescriptor() {
return descriptor;
@@ -572,7 +572,7 @@
* normal reference type (that is, a reference type and
* additionally not a return address).
*
- * @return non-null; the internal-form class name
+ * @return {@code non-null;} the internal-form class name
*/
public String getClassName() {
if (className == null) {
@@ -592,8 +592,8 @@
}
/**
- * Gets the category. Most instances are category 1. <code>long</code>
- * and <code>double</code> are the only category 2 types.
+ * Gets the category. Most instances are category 1. {@code long}
+ * and {@code double} are the only category 2 types.
*
* @see #isCategory1
* @see #isCategory2
@@ -649,7 +649,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</code>.
+ * {@code int}.
*
* @return whether this type is "intlike"
*/
@@ -695,7 +695,7 @@
* Gets whether this type is a normal reference type. A normal
* reference type is a reference type that is not a return
* address. This method is just convenient shorthand for
- * <code>getBasicType() == Type.BT_OBJECT</code>.
+ * {@code getBasicType() == Type.BT_OBJECT}.
*
* @return whether this type is a normal reference type
*/
@@ -705,7 +705,7 @@
/**
* Gets whether this type is an array type. If this method returns
- * <code>true</code>, then it is safe to use {@link #getComponentType}
+ * {@code true}, then it is safe to use {@link #getComponentType}
* to determine the component type.
*
* @return whether this type is an array type
@@ -726,7 +726,7 @@
/**
* Gets whether this type represents an uninitialized instance. An
- * uninitialized instance is what one gets back from the <code>new</code>
+ * uninitialized instance is what one gets back from the {@code new}
* opcode, and remains uninitialized until a valid constructor is
* invoked on it.
*
@@ -738,12 +738,12 @@
/**
* Gets the bytecode index at which this uninitialized type was
- * allocated. This returns <code>Integer.MAX_VALUE</code> if this
+ * allocated. This returns {@code Integer.MAX_VALUE} if this
* type is an uninitialized incoming parameter (i.e., the
- * <code>this</code> of an <code><init></code> method) or
- * <code>-1</code> if this type is in fact <i>initialized</i>.
+ * {@code this} of an {@code <init>} method) or
+ * {@code -1} if this type is in fact <i>initialized</i>.
*
- * @return >= -1; the allocation bytecode index
+ * @return {@code >= -1;} the allocation bytecode index
*/
public int getNewAt() {
return newAt;
@@ -753,7 +753,7 @@
* Gets the initialized type corresponding to this instance, but only
* if this instance is in fact an uninitialized object type.
*
- * @return non-null; the initialized type
+ * @return {@code non-null;} the initialized type
*/
public Type getInitializedType() {
if (initializedType == null) {
@@ -767,7 +767,7 @@
/**
* Gets the type corresponding to an array of this type.
*
- * @return non-null; the array type
+ * @return {@code non-null;} the array type
*/
public Type getArrayType() {
if (arrayType == null) {
@@ -781,7 +781,7 @@
* Gets the component type of this type. This method is only valid on
* array types.
*
- * @return non-null; the component type
+ * @return {@code non-null;} the component type
*/
public Type getComponentType() {
if (componentType == null) {
@@ -800,8 +800,8 @@
* it is indicated as uninitialized and allocated at the given bytecode
* index. This instance must be an initialized object type.
*
- * @param newAt >= 0; the allocation bytecode index
- * @return non-null; an appropriately-constructed instance
+ * @param newAt {@code >= 0;} the allocation bytecode index
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public Type asUninitialized(int newAt) {
if (newAt < 0) {
@@ -838,8 +838,8 @@
* there. If a conflicting value is already in the table, then leave it.
* Return the interned value.
*
- * @param type non-null; instance to make interned
- * @return non-null; the actual interned object
+ * @param type {@code non-null;} instance to make interned
+ * @return {@code non-null;} the actual interned object
*/
private static Type putIntern(Type type) {
synchronized (internTable) {
diff --git a/dx/src/com/android/dx/rop/type/TypeBearer.java b/dx/src/com/android/dx/rop/type/TypeBearer.java
index b9e4ea5..2f2f274 100644
--- a/dx/src/com/android/dx/rop/type/TypeBearer.java
+++ b/dx/src/com/android/dx/rop/type/TypeBearer.java
@@ -26,40 +26,40 @@
/**
* Gets the type associated with this instance.
*
- * @return non-null; the type
+ * @return {@code non-null;} the type
*/
public Type getType();
/**
* Gets the frame type corresponding to this type. This method returns
- * <code>this</code>, except if {@link Type#isIntlike} on the underlying
- * type returns <code>true</code> but the underlying type is not in
+ * {@code this}, except if {@link Type#isIntlike} on the underlying
+ * type returns {@code true} but the underlying type is not in
* fact {@link Type#INT}, in which case this method returns an instance
- * whose underlying type <i>is</i> <code>INT</code>.
+ * whose underlying type <i>is</i> {@code INT}.
*
- * @return non-null; the frame type for this instance
+ * @return {@code non-null;} the frame type for this instance
*/
public TypeBearer getFrameType();
/**
* Gets the basic type corresponding to this instance.
*
- * @return the basic type; one of the <code>BT_*</code> constants
+ * @return the basic type; one of the {@code BT_*} constants
* defined by {@link Type}
*/
public int getBasicType();
/**
* Gets the basic type corresponding to this instance's frame type. This
- * is equivalent to <code>getFrameType().getBasicType()</code>, and
- * is the same as calling <code>getFrameType()</code> unless this
+ * is equivalent to {@code getFrameType().getBasicType()}, and
+ * is the same as calling {@code getFrameType()} unless this
* instance is an int-like type, in which case this method returns
- * <code>BT_INT</code>.
+ * {@code BT_INT}.
*
* @see #getBasicType
* @see #getFrameType
*
- * @return the basic frame type; one of the <code>BT_*</code> constants
+ * @return the basic frame type; one of the {@code BT_*} constants
* defined by {@link Type}
*/
public int getBasicFrameType();
@@ -67,8 +67,8 @@
/**
* Returns whether this instance represents a constant value.
*
- * @return <code>true</code> if this instance represents a constant value
- * and <code>false</code> if not
+ * @return {@code true} if this instance represents a constant value
+ * and {@code false} if not
*/
public boolean isConstant();
}
diff --git a/dx/src/com/android/dx/rop/type/TypeList.java b/dx/src/com/android/dx/rop/type/TypeList.java
index 0944fe2..e82cca7 100644
--- a/dx/src/com/android/dx/rop/type/TypeList.java
+++ b/dx/src/com/android/dx/rop/type/TypeList.java
@@ -22,29 +22,29 @@
public interface TypeList {
/**
* Returns whether this instance is mutable. Note that the
- * <code>TypeList</code> interface itself doesn't provide any
+ * {@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</code> if this instance is mutable or
- * <code>false</code> if it is immutable
+ * @return {@code true} if this instance is mutable or
+ * {@code false} if it is immutable
*/
public boolean isMutable();
/**
* Gets the size of this list.
*
- * @return >= 0; the size
+ * @return {@code >= 0;} the size
*/
public int size();
/**
* 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</code>.
+ * will throw {@code NullPointerException}.
*
- * @param n >= 0, < size(); which element
- * @return non-null; the indicated element
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
*/
public Type getType(int n);
@@ -53,7 +53,7 @@
* all the elements of this list. This is a sum of the widths (categories)
* of all the elements.
*
- * @return >= 0; the required number of words
+ * @return {@code >= 0;} the required number of words
*/
public int getWordCount();
@@ -62,8 +62,8 @@
* the given item is appended to the end and it is guaranteed to be
* immutable.
*
- * @param type non-null; item to append
- * @return non-null; an appropriately-constructed instance
+ * @param type {@code non-null;} item to append
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public TypeList withAddedType(Type type);
}
diff --git a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
index 86fcf81..fdabaab 100644
--- a/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
+++ b/dx/src/com/android/dx/ssa/BasicRegisterMapper.java
@@ -24,17 +24,16 @@
* This class maps one register space into another, with
* each mapping built up individually and added via addMapping()
*/
-public class BasicRegisterMapper
- extends RegisterMapper {
-
+public class BasicRegisterMapper extends RegisterMapper {
/** indexed by old register, containing new name */
private IntList oldToNew;
- /** Running count of used registers in new namespace */
+ /** running count of used registers in new namespace */
private int runningCountNewRegisters;
/**
- * Creates a new OneToOneRegisterMapper
+ * Creates a new OneToOneRegisterMapper.
+ *
* @param countOldRegisters the number of registers in the old name space
*/
public BasicRegisterMapper(int countOldRegisters) {
@@ -70,15 +69,16 @@
/**
* Returns the new-namespace mapping for the specified
- * old-namespace register, or -1 if one exists
+ * old-namespace register, or -1 if one exists.
*
- * @param oldReg >=0; old-namespace register
- * @return new-namespace register or -1 if none.
+ * @param oldReg {@code >= 0;} old-namespace register
+ * @return new-namespace register or -1 if none
*/
public int oldToNew(int oldReg) {
- if(oldReg >= oldToNew.size()) {
+ if (oldReg >= oldToNew.size()) {
return -1;
}
+
return oldToNew.get(oldReg);
}
@@ -88,7 +88,8 @@
sb.append("Old\tNew\n");
int sz = oldToNew.size();
- for(int i = 0; i < sz; i++) {
+
+ for (int i = 0; i < sz; i++) {
sb.append(i);
sb.append('\t');
sb.append(oldToNew.get(i));
@@ -104,12 +105,12 @@
}
/**
- * adds a mapping to the mapper. If oldReg has already been mapped,
+ * Adds a mapping to the mapper. If oldReg has already been mapped,
* overwrites previous mapping with new mapping.
*
- * @param oldReg >=0
- * @param newReg >=0
- * @param category width of reg (1 or 2)
+ * @param oldReg {@code >= 0;} old register
+ * @param newReg {@code >= 0;} new register
+ * @param category {@code 1..2;} width of reg
*/
public void addMapping(int oldReg, int newReg, int category) {
if (oldReg >= oldToNew.size()) {
@@ -118,6 +119,7 @@
oldToNew.add(-1);
}
}
+
oldToNew.set(oldReg, newReg);
if (runningCountNewRegisters < (newReg + category)) {
diff --git a/dx/src/com/android/dx/ssa/ConstCollector.java b/dx/src/com/android/dx/ssa/ConstCollector.java
index afdede7..03252d1 100644
--- a/dx/src/com/android/dx/ssa/ConstCollector.java
+++ b/dx/src/com/android/dx/ssa/ConstCollector.java
@@ -17,19 +17,20 @@
package com.android.dx.ssa;
import com.android.dx.rop.code.*;
-import com.android.dx.rop.type.TypeBearer;
+import com.android.dx.rop.cst.Constant;
+import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.cst.TypedConstant;
import com.android.dx.rop.type.StdTypeList;
import com.android.dx.rop.type.Type;
-import com.android.dx.rop.cst.Constant;
-import com.android.dx.rop.cst.TypedConstant;
-import com.android.dx.rop.cst.CstString;
+import com.android.dx.rop.type.TypeBearer;
-import java.util.HashMap;
import java.util.ArrayList;
-import java.util.Iterator;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
/**
* Collects constants that are used more than once at the top of the
@@ -37,7 +38,6 @@
* insn size by about 3%.
*/
public class ConstCollector {
-
/** Maximum constants to collect per method. Puts cap on reg use */
private static final int MAX_COLLECTED_CONSTANTS = 5;
@@ -60,18 +60,20 @@
private final SsaMethod ssaMeth;
/**
- * Process a method.
+ * Processes a method.
*
- * @param ssaMethod non-null; method to process
+ * @param ssaMethod {@code non-null;} method to process
*/
public static void process(SsaMethod ssaMethod) {
- ConstCollector dc;
-
- dc = new ConstCollector(ssaMethod);
-
- dc.run();
+ ConstCollector cc = new ConstCollector(ssaMethod);
+ cc.run();
}
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMethod {@code non-null;} method to process
+ */
private ConstCollector(SsaMethod ssaMethod) {
this.ssaMeth = ssaMethod;
}
@@ -111,9 +113,7 @@
SsaBasicBlock successorBlock
= entryBlock.getPrimarySuccessor();
- /*
- * Insert a block containing the const insn
- */
+ // Insert a block containing the const insn.
SsaBasicBlock constBlock
= entryBlock.insertNewSuccessor(successorBlock);
@@ -122,18 +122,17 @@
RegisterSpecList.EMPTY,
StdTypeList.EMPTY, cst));
- /*
- * Insert a block containing the move-result-pseudo insn
- */
+ // Insert a block containing the move-result-pseudo insn.
SsaBasicBlock resultBlock
= constBlock.insertNewSuccessor(successorBlock);
+ PlainInsn insn
+ = new PlainInsn(
+ Rops.opMoveResultPseudo(result.getTypeBearer()),
+ SourcePosition.NO_INFO,
+ result, RegisterSpecList.EMPTY);
- resultBlock.addInsnToHead(
- new PlainInsn(
- Rops.opMoveResultPseudo(result.getTypeBearer()),
- SourcePosition.NO_INFO,
- result, RegisterSpecList.EMPTY));
+ resultBlock.addInsnToHead(insn);
}
newRegs.put(cst, result);
@@ -147,7 +146,7 @@
* sorted by most used first. Skips non-collectable consts, such as
* non-string object constants
*
- * @return non-null; list of constants in most-to-least used order
+ * @return {@code non-null;} list of constants in most-to-least used order
*/
private ArrayList<TypedConstant> getConstsSortedByCountUse() {
int regSz = ssaMeth.getRegCount();
@@ -155,20 +154,21 @@
final HashMap<TypedConstant, Integer> countUses
= new HashMap<TypedConstant, Integer>();
- // Each collected constant can be used by just one local
- // (used only if COLLECT_ONE_LOCAL is true)
+ /*
+ * Each collected constant can be used by just one local
+ * (used only if COLLECT_ONE_LOCAL is true).
+ */
final HashSet<TypedConstant> usedByLocal
= new HashSet<TypedConstant>();
- // Count how many times each const value is used
+ // Count how many times each const value is used.
for (int i = 0; i < regSz; i++) {
SsaInsn insn = ssaMeth.getDefinitionForRegister(i);
if (insn == null) continue;
RegisterSpec result = insn.getResult();
-
- TypeBearer typeBearer = insn.getResult().getTypeBearer();
+ TypeBearer typeBearer = result.getTypeBearer();
if (!typeBearer.isConstant()) continue;
@@ -177,28 +177,30 @@
if (insn.canThrow()) {
/*
* Don't move anything other than strings -- the risk
- * of changing where an exception is thrown is too high.
+ * of changing where an exception is thrown is too high.
*/
if (!(cst instanceof CstString) || !COLLECT_STRINGS) {
continue;
}
/*
- * We can't move any throwable const whose throw will be caught,
- * so don't count them.
+ * We can't move any throwable const whose throw will be
+ * caught, so don't count them.
*/
if (insn.getBlock().getSuccessors().cardinality() > 1) {
continue;
}
}
- // TODO might be nice to try and figure out which local wins most
- // when collected
+ /*
+ * TODO: Might be nice to try and figure out which local
+ * wins most when collected.
+ */
if (ssaMeth.isRegALocal(result)) {
if (!COLLECT_ONE_LOCAL) {
continue;
} else {
if (usedByLocal.contains(cst)) {
- // Count one local usage only
+ // Count one local usage only.
continue;
} else {
usedByLocal.add(cst);
@@ -214,18 +216,15 @@
}
}
- // Collect constants that have been reused
- Iterator<TypedConstant> it = countUses.keySet().iterator();
+ // Collect constants that have been reused.
ArrayList<TypedConstant> constantList = new ArrayList<TypedConstant>();
- while (it.hasNext()) {
- TypedConstant cst = it.next();
-
- if (countUses.get(cst) > 1) {
- constantList.add(cst);
+ for (Map.Entry<TypedConstant, Integer> entry : countUses.entrySet()) {
+ if (entry.getValue() > 1) {
+ constantList.add(entry.getKey());
}
}
- // Sort by use, with most used at the beginning of the list
+ // Sort by use, with most used at the beginning of the list.
Collections.sort(constantList, new Comparator<Constant>() {
public int compare(Constant a, Constant b) {
int ret;
@@ -241,47 +240,48 @@
return ret;
}
+
public boolean equals (Object obj) {
return obj == this;
}
});
+
return constantList;
}
/**
* Inserts mark-locals if necessary when changing a register. If
- * the definition of <code>origReg</code> is associated with a local
- * variable, then insert a mark-local for <code>newReg</code> just below
- * it. We expect the definition of <code>origReg</code> to ultimately
+ * the definition of {@code origReg} is associated with a local
+ * 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 non-null; original register
- * @param newReg non-null; new register that will replace
- * <code>origReg</code>
+ * @param origReg {@code non-null;} original register
+ * @param newReg {@code non-null;} new register that will replace
+ * {@code origReg}
*/
- private void fixLocalAssignment(RegisterSpec origReg, RegisterSpec newReg) {
- for (SsaInsn use: ssaMeth.getUseListForRegister(origReg.getReg())) {
+ private void fixLocalAssignment(RegisterSpec origReg,
+ RegisterSpec newReg) {
+ for (SsaInsn use : ssaMeth.getUseListForRegister(origReg.getReg())) {
RegisterSpec localAssignment = use.getLocalAssignment();
if (localAssignment == null) {
continue;
}
if (use.getResult() == null) {
- // this is a mark-local. it will be updated when all uses
- // are updated
+ /*
+ * This is a mark-local. it will be updated when all uses
+ * are updated.
+ */
continue;
}
LocalItem local = localAssignment.getLocalItem();
- /*
- * un-associate original use
- */
+ // Un-associate original use.
use.setResultLocal(null);
- /*
- * now add a mark-local to the new reg immediately after
- */
+ // Now add a mark-local to the new reg immediately after.
newReg = newReg.withLocalItem(local);
SsaInsn newInsn
@@ -301,15 +301,17 @@
* Updates all uses of various consts to use the values in the newly
* assigned registers.
*
- * @param newRegs non-null; mapping between constant and new reg
- * @param origRegCount >=0; original SSA reg count, not including
+ * @param newRegs {@code non-null;} mapping between constant and new reg
+ * @param origRegCount {@code >=0;} original SSA reg count, not including
* newly added constant regs
*/
private void updateConstUses(HashMap<TypedConstant, RegisterSpec> newRegs,
int origRegCount) {
- // Set of constants associated with a local variable
- // Used only if COLLECT_ONE_LOCAL is true
+ /*
+ * set of constants associated with a local variable; used
+ * only if COLLECT_ONE_LOCAL is true.
+ */
final HashSet<TypedConstant> usedByLocal
= new HashSet<TypedConstant>();
@@ -338,8 +340,11 @@
if (!COLLECT_ONE_LOCAL) {
continue;
} else {
- // TODO if the same local gets the same cst multiple times,
- // it would be nice to reuse the register
+ /*
+ * TODO: If the same local gets the same cst
+ * multiple times, it would be nice to reuse the
+ * register.
+ */
if (usedByLocal.contains(cst)) {
continue;
} else {
@@ -349,7 +354,7 @@
}
}
- // Maps an original const register to the new collected register
+ // maps an original const register to the new collected register
RegisterMapper mapper = new RegisterMapper() {
@Override
public int getNewRegisterCount() {
@@ -359,14 +364,15 @@
@Override
public RegisterSpec map(RegisterSpec registerSpec) {
if (registerSpec.getReg() == origReg.getReg()) {
- return newReg.withLocalItem(registerSpec.getLocalItem());
+ return newReg.withLocalItem(
+ registerSpec.getLocalItem());
}
return registerSpec;
}
};
- for (SsaInsn use: useList[origReg.getReg()]) {
+ for (SsaInsn use : useList[origReg.getReg()]) {
if (use.canThrow()
&& use.getBlock().getSuccessors().cardinality() > 1) {
continue;
diff --git a/dx/src/com/android/dx/ssa/DeadCodeRemover.java b/dx/src/com/android/dx/ssa/DeadCodeRemover.java
index 4fded44..ec960b8 100644
--- a/dx/src/com/android/dx/ssa/DeadCodeRemover.java
+++ b/dx/src/com/android/dx/ssa/DeadCodeRemover.java
@@ -36,55 +36,55 @@
* block to entry block.
*/
public class DeadCodeRemover {
-
/** method we're processing */
- private SsaMethod ssaMeth;
+ private final SsaMethod ssaMeth;
+
/** ssaMeth.getRegCount() */
- private int regCount;
+ private final int regCount;
/**
* indexed by register: whether reg should be examined
* (does it correspond to a no-side-effect insn?)
*/
- private BitSet worklist;
+ private final BitSet worklist;
/** use list indexed by register; modified during operation */
- private ArrayList<SsaInsn>[] useList;
+ private final ArrayList<SsaInsn>[] useList;
/**
* Process a method with the dead-code remver
+ *
* @param ssaMethod method to process
*/
public static void process(SsaMethod ssaMethod) {
- DeadCodeRemover dc;
-
- dc = new DeadCodeRemover(ssaMethod);
-
+ DeadCodeRemover dc = new DeadCodeRemover(ssaMethod);
dc.run();
}
+ /**
+ * Constructs an instance.
+ *
+ * @param ssaMethod method to process
+ */
private DeadCodeRemover(SsaMethod ssaMethod) {
this.ssaMeth = ssaMethod;
regCount = ssaMethod.getRegCount();
-
worklist = new BitSet(regCount);
-
useList = ssaMeth.getUseListCopy();
}
/**
- * Run the dead code remover
+ * Runs the dead code remover.
*/
private void run() {
-
HashSet<SsaInsn> deletedInsns = (HashSet<SsaInsn>) new HashSet();
ssaMeth.forEachInsn(new NoSideEffectVisitor(worklist));
int regV;
- while ( 0 <= (regV = worklist.nextSetBit(0)) ) {
+ while ( 0 <= (regV = worklist.nextSetBit(0)) ) {
worklist.clear(regV);
if (useList[regV].size() == 0
@@ -92,7 +92,7 @@
SsaInsn insnS = ssaMeth.getDefinitionForRegister(regV);
- // This insn has already been deleted
+ // This insn has already been deleted.
if (deletedInsns.contains(insnS)) {
continue;
}
@@ -101,8 +101,7 @@
int sz = sources.size();
for (int i = 0; i < sz; i++) {
-
- // Delete this insn from all usage lists
+ // Delete this insn from all usage lists.
RegisterSpec source = sources.get(i);
useList[source.getReg()].remove(insnS);
@@ -110,14 +109,14 @@
ssaMeth.getDefinitionForRegister(
source.getReg()))) {
/*
- * Only registers who's definition has no side effect
- * should be added back to the worklist
+ * Only registers whose definition has no side effect
+ * should be added back to the worklist.
*/
worklist.set(source.getReg());
}
}
- // Schedule this insn for later deletion
+ // Schedule this insn for later deletion.
deletedInsns.add(insnS);
}
}
@@ -127,7 +126,8 @@
/**
* Returns true if the only uses of this register form a circle of
- * operations with no side effects
+ * 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
@@ -139,7 +139,7 @@
return true;
}
- for (SsaInsn use: useList[regV]) {
+ for (SsaInsn use : useList[regV]) {
if (hasSideEffect(use)) {
return false;
}
@@ -152,7 +152,7 @@
// This register is only used in operations that have no side effect.
set.set(regV);
- for (SsaInsn use: useList[regV]) {
+ for (SsaInsn use : useList[regV]) {
RegisterSpec result = use.getResult();
if (result == null
@@ -167,13 +167,14 @@
/**
* Returns true if this insn has a side-effect. Returns true
* if the insn is null for reasons stated in the code block.
- * @param insn null-ok; instruction in question
+ *
+ * @param insn {@code null-ok;} instruction in question
* @return true if it has a side-effect
*/
private static boolean hasSideEffect(SsaInsn insn) {
if (insn == null) {
- /* while false would seem to make more sense here, true
- * prevents us from adding this back to a worklist unnecessarally
+ /* While false would seem to make more sense here, true
+ * prevents us from adding this back to a worklist unnecessarally.
*/
return true;
}
@@ -185,7 +186,7 @@
* A callback class used to build up the initial worklist of
* registers defined by an instruction with no side effect.
*/
- static class NoSideEffectVisitor implements SsaInsn.Visitor {
+ static private class NoSideEffectVisitor implements SsaInsn.Visitor {
BitSet noSideEffectRegs;
/**
@@ -195,13 +196,13 @@
* @param noSideEffectRegs to-build bitset of regs that are
* results of regs with no side effects
*/
- NoSideEffectVisitor(BitSet noSideEffectRegs) {
+ public NoSideEffectVisitor(BitSet noSideEffectRegs) {
this.noSideEffectRegs = noSideEffectRegs;
}
/** {@inheritDoc} */
public void visitMoveInsn (NormalSsaInsn insn) {
- // If we're tracking local vars, some moves have side effects
+ // If we're tracking local vars, some moves have side effects.
if (!hasSideEffect(insn)) {
noSideEffectRegs.set(insn.getResult().getReg());
}
@@ -209,7 +210,7 @@
/** {@inheritDoc} */
public void visitPhiInsn (PhiInsn phi) {
- // If we're tracking local vars, then some phis have side effects
+ // If we're tracking local vars, then some phis have side effects.
if (!hasSideEffect(phi)) {
noSideEffectRegs.set(phi.getResult().getReg());
}
diff --git a/dx/src/com/android/dx/ssa/DomFront.java b/dx/src/com/android/dx/ssa/DomFront.java
index ea089ec..3005015 100644
--- a/dx/src/com/android/dx/ssa/DomFront.java
+++ b/dx/src/com/android/dx/ssa/DomFront.java
@@ -30,27 +30,34 @@
* Harvey, and Kennedy; transliterated to Java.
*/
public class DomFront {
+ /** local debug flag */
private static boolean DEBUG = false;
+ /** {@code non-null;} method being processed */
private final SsaMethod meth;
+
private final ArrayList<SsaBasicBlock> nodes;
+
private final DomInfo[] domInfos;
/**
* Dominance-frontier information for a single basic block.
*/
public static class DomInfo {
- /** non-null; the dominance frontier set indexed by block index */
- IntSet dominanceFrontiers;
- /** >= 0 after run(); the index of the immediate dominator */
- int idom = -1;
- /** depth-first traversal index */
- int traversalIndex;
+ /**
+ * {@code null-ok;} the dominance frontier set indexed by
+ * block index
+ */
+ public IntSet dominanceFrontiers;
+
+ /** {@code >= 0 after run();} the index of the immediate dominator */
+ public int idom = -1;
}
/**
* Constructs instance. Call {@link DomFront#run} to process.
- * @param meth
+ *
+ * @param meth {@code non-null;} method to process
*/
public DomFront(SsaMethod meth) {
this.meth = meth;
@@ -67,7 +74,7 @@
/**
* Calculates the dominance frontier information for the method.
*
- * @return non-null; an array of DomInfo structures
+ * @return {@code non-null;} an array of DomInfo structures
*/
public DomInfo[] run() {
int szNodes = nodes.size();
@@ -80,8 +87,7 @@
}
}
- Dominators methDom = new Dominators(domInfos, false);
- methDom.run(meth);
+ Dominators methDom = Dominators.make(meth, domInfos, false);
if (DEBUG) {
for (int i = 0; i < szNodes; i++) {
@@ -123,7 +129,7 @@
sb.append('{');
boolean comma = false;
- for (SsaBasicBlock child: node.getDomChildren()) {
+ for (SsaBasicBlock child : node.getDomChildren()) {
if (comma) {
sb.append(',');
}
@@ -164,20 +170,25 @@
SsaBasicBlock nb = nodes.get(b);
DomInfo nbInfo = domInfos[b];
BitSet pred = nb.getPredecessors();
+
if (pred.cardinality() > 1) {
for (int i = pred.nextSetBit(0); i >= 0;
i = pred.nextSetBit(i + 1)) {
- for(int runnerIndex = i
- ; runnerIndex != nbInfo.idom
- ;) {
- // We can stop if we hit a block we already
- // added label to, since we must be at a part
- // of the dom tree we have seen before.
+ for (int runnerIndex = i;
+ runnerIndex != nbInfo.idom; /* empty */) {
+ /*
+ * We can stop if we hit a block we already
+ * added label to, since we must be at a part
+ * of the dom tree we have seen before.
+ */
DomInfo runnerInfo = domInfos[runnerIndex];
- if (runnerInfo.dominanceFrontiers.has(b))
+
+ if (runnerInfo.dominanceFrontiers.has(b)) {
break;
- // "add b to runner's dominance frontier set"
+ }
+
+ // Add b to runner's dominance frontier set.
runnerInfo.dominanceFrontiers.add(b);
runnerIndex = runnerInfo.idom;
}
diff --git a/dx/src/com/android/dx/ssa/Dominators.java b/dx/src/com/android/dx/ssa/Dominators.java
index 1af2cbc..f7d7da6 100644
--- a/dx/src/com/android/dx/ssa/Dominators.java
+++ b/dx/src/com/android/dx/ssa/Dominators.java
@@ -41,31 +41,55 @@
* rank to keep the union-find tree balanced.
*/
public final class Dominators {
- /* postdom is true if we want post dominators. */
- private boolean postdom;
+ /* postdom is true if we want post dominators */
+ private final boolean postdom;
+
+ /* {@code non-null;} method being processed */
+ private final SsaMethod meth;
+
/* Method's basic blocks. */
- private ArrayList<SsaBasicBlock> blocks;
+ private final ArrayList<SsaBasicBlock> blocks;
- private static final class DFSInfo {
- int semidom;
- SsaBasicBlock parent;
- // rep(resentative) is known as "label" in the paper. It is the node
- // that our block's DFS info has been unioned to.
- SsaBasicBlock rep;
- SsaBasicBlock ancestor;
- ArrayList<SsaBasicBlock> bucket;
+ /** indexed by basic block index */
+ private final DFSInfo[] info;
- public DFSInfo() {
- bucket = new ArrayList<SsaBasicBlock>();
- }
+ private final ArrayList<SsaBasicBlock> vertex;
+ /** {@code non-null;} the raw dominator info */
+ private final DomFront.DomInfo domInfos[];
+
+ /**
+ * 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
+ */
+ private Dominators(SsaMethod meth, DomFront.DomInfo[] domInfos,
+ boolean postdom) {
+ this.meth = meth;
+ this.domInfos = domInfos;
+ this.postdom = postdom;
+ this.blocks = meth.getBlocks();
+ this.info = new DFSInfo[blocks.size() + 2];
+ this.vertex = new ArrayList<SsaBasicBlock>();
}
- /** Indexed by basic block index */
- private DFSInfo[] info;
- private ArrayList<SsaBasicBlock> vertex;
+ /**
+ * 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
+ */
+ public static Dominators make(SsaMethod meth, DomFront.DomInfo[] domInfos,
+ boolean postdom) {
+ Dominators result = new Dominators(meth, domInfos, postdom);
- private DomFront.DomInfo domInfos[];
+ result.run();
+ return result;
+ }
private BitSet getSuccs(SsaBasicBlock block) {
if (postdom) {
@@ -85,6 +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) {
@@ -110,7 +135,7 @@
}
worklist.remove(wsize - 1);
- // Update based on ancestor info
+ // Update based on ancestor info.
if (vabbInfo.ancestor == null) {
continue;
}
@@ -124,42 +149,25 @@
}
}
}
+
private SsaBasicBlock eval(SsaBasicBlock v) {
DFSInfo bbInfo = info[v.getIndex()];
+
if (bbInfo.ancestor == null) {
return v;
}
+
compress(v);
return bbInfo.rep;
}
/**
- * Callback for depth-first walk through control flow graph (either
- * from the entry block or the exit block). Records the traversal order
- * in the <code>info</code>list.
+ * Performs dominator/post-dominator calculation for the control
+ * flow graph.
+ *
+ * @param meth {@code non-null;} method to analyze
*/
- private class DfsWalker implements SsaBasicBlock.Visitor {
- int dfsNum = 0;
-
- public void visitBlock (SsaBasicBlock v, SsaBasicBlock parent) {
- DFSInfo bbInfo = new DFSInfo();
- bbInfo.semidom = ++dfsNum;
- bbInfo.rep = v;
- bbInfo.parent = parent;
- vertex.add(v);
- info[v.getIndex()] = bbInfo;
- }
- }
-
- /**
- * Performs dominator/post-dominator calculation for the control flow graph.
- * @param meth Method to analyze
- */
- public void run(SsaMethod meth) {
-
- this.blocks = meth.getBlocks();
- this.info = new DFSInfo[blocks.size() + 2];
- this.vertex = new ArrayList<SsaBasicBlock>();
+ private void run() {
SsaBasicBlock root = postdom
? meth.getExitBlock() : meth.getEntryBlock();
@@ -168,8 +176,10 @@
domInfos[root.getIndex()].idom = root.getIndex();
}
- // First we perform a DFS numbering of the blocks, by numbering the dfs
- // tree roots
+ /*
+ * First we perform a DFS numbering of the blocks, by
+ * numbering the dfs tree roots.
+ */
DfsWalker walker = new DfsWalker();
meth.forEachBlockDepthFirst(postdom, walker);
@@ -184,12 +194,15 @@
BitSet preds = getPreds(w);
for (int j = preds.nextSetBit(0);
- j >= 0;
- j = preds.nextSetBit(j + 1)) {
+ j >= 0;
+ j = preds.nextSetBit(j + 1)) {
SsaBasicBlock predBlock = blocks.get(j);
DFSInfo predInfo = info[predBlock.getIndex()];
- // PredInfo may not exist in case the predecessor is not
- // reachable
+
+ /*
+ * PredInfo may not exist in case the predecessor is
+ * not reachable.
+ */
if (predInfo != null) {
int predSemidom = info[eval(predBlock).getIndex()].semidom;
if (predSemidom < wInfo.semidom) {
@@ -199,11 +212,14 @@
}
info[vertex.get(wInfo.semidom).getIndex()].bucket.add(w);
- // Normally we would call link here, but in our m log n
- // implementation this is equivalent to the following single line
+ /*
+ * Normally we would call link here, but in our O(m log n)
+ * implementation this is equivalent to the following
+ * single line.
+ */
wInfo.ancestor = wInfo.parent;
- // Implicity define idom for each vertex
+ // Implicity define idom for each vertex.
ArrayList<SsaBasicBlock> wParentBucket;
wParentBucket = info[wInfo.parent.getIndex()].bucket;
@@ -219,6 +235,7 @@
}
}
}
+
// Now explicitly define the immediate dominator of each vertex
for (int i = 2; i <= dfsMax; ++i) {
SsaBasicBlock w = vertex.get(i);
@@ -231,10 +248,38 @@
}
/**
- * @param postdom true for postdom information, false for normal dom info
+ * Callback for depth-first walk through control flow graph (either
+ * from the entry block or the exit block). Records the traversal order
+ * in the {@code info}list.
*/
- public Dominators(DomFront.DomInfo[] domInfos, boolean postdom) {
- this.domInfos = domInfos;
- this.postdom = postdom;
+ private class DfsWalker implements SsaBasicBlock.Visitor {
+ private int dfsNum = 0;
+
+ public void visitBlock(SsaBasicBlock v, SsaBasicBlock parent) {
+ DFSInfo bbInfo = new DFSInfo();
+ bbInfo.semidom = ++dfsNum;
+ bbInfo.rep = v;
+ bbInfo.parent = parent;
+ vertex.add(v);
+ info[v.getIndex()] = bbInfo;
+ }
+ }
+
+ private static final class DFSInfo {
+ public int semidom;
+ public SsaBasicBlock parent;
+
+ /**
+ * rep(resentative) is known as "label" in the paper. It is the node
+ * that our block's DFS info has been unioned to.
+ */
+ public SsaBasicBlock rep;
+
+ public SsaBasicBlock ancestor;
+ public ArrayList<SsaBasicBlock> bucket;
+
+ public DFSInfo() {
+ bucket = new ArrayList<SsaBasicBlock>();
+ }
}
}
diff --git a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
index be678dd..392579d 100644
--- a/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
+++ b/dx/src/com/android/dx/ssa/InterferenceRegisterMapper.java
@@ -33,7 +33,6 @@
* have variable register widths/categories, and the new namespace does.
*/
public class InterferenceRegisterMapper extends BasicRegisterMapper {
-
/**
* Array of interference sets. ArrayList is indexed by new namespace
* and BitIntSet's are indexed by old namespace. The list expands
@@ -45,16 +44,15 @@
*/
private final ArrayList<BitIntSet> newRegInterference;
- /**
- * The interference graph for the old namespace
- */
+ /** the interference graph for the old namespace */
private final InterferenceGraph oldRegInterference;
/**
- * @param countOldRegisters number of registers in old namespace.
+ * Constructs an instance
+ *
+ * @param countOldRegisters number of registers in old namespace
*/
- public InterferenceRegisterMapper(
- InterferenceGraph oldRegInterference,
+ public InterferenceRegisterMapper(InterferenceGraph oldRegInterference,
int countOldRegisters) {
super(countOldRegisters);
@@ -75,8 +73,8 @@
}
/**
- * Checks to see if old namespace reg <code>oldReg</code> interferes
- * with what currently maps to <code>newReg</code>.
+ * Checks to see if old namespace reg {@code oldReg} interferes
+ * with what currently maps to {@code newReg}.
*
* @param oldReg old namespace register
* @param newReg new namespace register
@@ -101,10 +99,10 @@
}
/**
- * Checks to see if old namespace reg <code>oldReg</code> interferes
- * with what currently maps to <code>newReg</code>.
+ * Checks to see if old namespace reg {@code oldReg} interferes
+ * with what currently maps to {@code newReg}.
*
- * @param oldSpec non-null; old namespace register
+ * @param oldSpec {@code non-null;} old namespace register
* @param newReg new namespace register
* @return true if oldReg will interfere with newReg
*/
@@ -115,6 +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
*/
@@ -134,17 +133,17 @@
* pinned to the specified new-namespace reg + category. Takes into
* account the category of the old-namespace registers.
*
- * @param oldSpecs non-null; set of old-namespace regs
- * @param newReg >= 0 new-namespace register
- * @param targetCategory 1 or 2; the number of adjacent new-namespace
+ * @param oldSpecs {@code non-null;} set of old-namespace regs
+ * @param newReg {@code >= 0;} new-namespace register
+ * @param targetCategory {@code 1..2;} the number of adjacent new-namespace
* registers (starting at ropReg) to consider
* @return true if any of the old-namespace register have been mapped
* to the new-namespace register + category
*/
public boolean areAnyPinned(RegisterSpecList oldSpecs,
int newReg, int targetCategory) {
-
int sz = oldSpecs.size();
+
for (int i = 0; i < sz; i++) {
RegisterSpec oldSpec = oldSpecs.get(i);
int r = oldToNew(oldSpec.getReg());
@@ -159,6 +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 ad10cd7..a70b5bb 100644
--- a/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
+++ b/dx/src/com/android/dx/ssa/LiteralOpUpgrader.java
@@ -42,7 +42,7 @@
/**
* Process a method.
*
- * @param ssaMethod non-null; method to process
+ * @param ssaMethod {@code non-null;} method to process
*/
public static void process(SsaMethod ssaMethod) {
LiteralOpUpgrader dc;
@@ -135,8 +135,8 @@
*
* TODO move this somewhere else.
*
- * @param insn non-null; an SsaInsn containing a PlainInsn
- * @param newSources non-null; new sources list for new insn
+ * @param insn {@code non-null;} an SsaInsn containing a PlainInsn
+ * @param newSources {@code non-null;} new sources list for new insn
* @param newOpcode A RegOp from {@link RegOps}
*/
private void replacePlainInsn(NormalSsaInsn insn,
diff --git a/dx/src/com/android/dx/ssa/LocalVariableExtractor.java b/dx/src/com/android/dx/ssa/LocalVariableExtractor.java
index 21c306b..11d53cf 100644
--- a/dx/src/com/android/dx/ssa/LocalVariableExtractor.java
+++ b/dx/src/com/android/dx/ssa/LocalVariableExtractor.java
@@ -33,23 +33,23 @@
* converted, and adapted through edge-splitting.
*/
public class LocalVariableExtractor {
- /** non-null; method being extracted from */
+ /** {@code non-null;} method being extracted from */
private final SsaMethod method;
- /** non-null; block list for the method */
+ /** {@code non-null;} block list for the method */
private final ArrayList<SsaBasicBlock> blocks;
- /** non-null; result in-progress */
+ /** {@code non-null;} result in-progress */
private final LocalVariableInfo resultInfo;
- /** non-null; work set indicating blocks needing to be processed */
+ /** {@code non-null;} work set indicating blocks needing to be processed */
private final BitSet workSet;
/**
* Extracts out all the local variable information from the given method.
*
- * @param method non-null; the method to extract from
- * @return non-null; the extracted information
+ * @param method {@code non-null;} the method to extract from
+ * @return {@code non-null;} the extracted information
*/
public static LocalVariableInfo extract(SsaMethod method) {
LocalVariableExtractor lve = new LocalVariableExtractor(method);
@@ -59,7 +59,7 @@
/**
* Constructs an instance. This method is private. Use {@link #extract}.
*
- * @param method non-null; the method to extract from
+ * @param method {@code non-null;} the method to extract from
*/
private LocalVariableExtractor(SsaMethod method) {
if (method == null) {
@@ -77,7 +77,7 @@
/**
* Does the extraction.
*
- * @return non-null; the extracted information
+ * @return {@code non-null;} the extracted information
*/
private LocalVariableInfo doit() {
@@ -98,7 +98,7 @@
/**
* Processes a single block.
*
- * @param blockIndex >= 0; block index of the block to process
+ * @param blockIndex {@code >= 0;} block index of the block to process
*/
private void processBlock(int blockIndex) {
RegisterSpecSet primaryState
diff --git a/dx/src/com/android/dx/ssa/LocalVariableInfo.java b/dx/src/com/android/dx/ssa/LocalVariableInfo.java
index f7c37d2..8845270 100644
--- a/dx/src/com/android/dx/ssa/LocalVariableInfo.java
+++ b/dx/src/com/android/dx/ssa/LocalVariableInfo.java
@@ -29,30 +29,30 @@
* Stolen from {@link com.android.dx.rop.code.LocalVariableInfo}.
*/
public class LocalVariableInfo extends MutabilityControl {
- /** >= 0; the register count for the method */
+ /** {@code >= 0;} the register count for the method */
private final int regCount;
/**
- * non-null; {@link com.android.dx.rop.code.RegisterSpecSet} to use when indicating a block
+ * {@code non-null;} {@link com.android.dx.rop.code.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
*/
private final RegisterSpecSet emptySet;
/**
- * non-null; array consisting of register sets representing the
+ * {@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 indices
*/
private final RegisterSpecSet[] blockStarts;
- /** non-null; map from instructions to the variable each assigns */
+ /** {@code non-null;} map from instructions to the variable each assigns */
private final HashMap<SsaInsn, RegisterSpec> insnAssignments;
/**
* Constructs an instance.
*
- * @param method non-null; the method being represented by this instance
+ * @param method {@code non-null;} the method being represented by this instance
*/
public LocalVariableInfo(SsaMethod method) {
if (method == null) {
@@ -74,8 +74,8 @@
* Sets the register set associated with the start of the block with
* the given index.
*
- * @param index >= 0; the block index
- * @param specs non-null; the register set to associate with the block
+ * @param index {@code >= 0;} the block index
+ * @param specs {@code non-null;} the register set to associate with the block
*/
public void setStarts(int index, RegisterSpecSet specs) {
throwIfImmutable();
@@ -99,12 +99,12 @@
* merge the two sets and call {@link #setStarts} on the result of the
* merge.
*
- * @param index >= 0; the block index
- * @param specs non-null; the register set to merge into the start set
+ * @param index {@code >= 0;} the block index
+ * @param specs {@code non-null;} the register set to merge into the start set
* for the block
- * @return <code>true</code> if the merge resulted in an actual change
+ * @return {@code true} if the merge resulted in an actual change
* to the associated set (including storing one for the first time) or
- * <code>false</code> if there was no change
+ * {@code false} if there was no change
*/
public boolean mergeStarts(int index, RegisterSpecSet specs) {
RegisterSpecSet start = getStarts0(index);
@@ -133,8 +133,8 @@
* with the given index. This returns an empty set with the appropriate
* max size if no set was associated with the block in question.
*
- * @param index >= 0; the block index
- * @return non-null; the associated register set
+ * @param index {@code >= 0;} the block index
+ * @return {@code non-null;} the associated register set
*/
public RegisterSpecSet getStarts(int index) {
RegisterSpecSet result = getStarts0(index);
@@ -145,10 +145,10 @@
/**
* Gets the register set associated with the start of the given
* block. This is just convenient shorthand for
- * <code>getStarts(block.getLabel())</code>.
+ * {@code getStarts(block.getLabel())}.
*
- * @param block non-null; the block in question
- * @return non-null; the associated register set
+ * @param block {@code non-null;} the block in question
+ * @return {@code non-null;} the associated register set
*/
public RegisterSpecSet getStarts(SsaBasicBlock block) {
return getStarts(block.getIndex());
@@ -160,8 +160,8 @@
* newly-allocated empty {@link RegisterSpecSet} of appropriate
* max size if there is not yet any set associated with the block.
*
- * @param index >= 0; the block index
- * @return non-null; the associated register set
+ * @param index {@code >= 0;} the block index
+ * @return {@code non-null;} the associated register set
*/
public RegisterSpecSet mutableCopyOfStarts(int index) {
RegisterSpecSet result = getStarts0(index);
@@ -181,8 +181,8 @@
* simple type and the one in the instruction can be an arbitrary
* {@link com.android.dx.rop.type.TypeBearer} (such as a constant value).
*
- * @param insn non-null; the instruction in question
- * @param spec non-null; the associated register spec
+ * @param insn {@code non-null;} the instruction in question
+ * @param spec {@code non-null;} the associated register spec
*/
public void addAssignment(SsaInsn insn, RegisterSpec spec) {
throwIfImmutable();
@@ -202,8 +202,8 @@
* Gets the named register being assigned by the given instruction, if
* previously stored in this instance.
*
- * @param insn non-null; instruction in question
- * @return null-ok; the named register being assigned, if any
+ * @param insn {@code non-null;} instruction in question
+ * @return {@code null-ok;} the named register being assigned, if any
*/
public RegisterSpec getAssignment(SsaInsn insn) {
return insnAssignments.get(insn);
@@ -212,7 +212,7 @@
/**
* Gets the number of assignments recorded by this instance.
*
- * @return >= 0; the number of assignments
+ * @return {@code >= 0;} the number of assignments
*/
public int getAssignmentCount() {
return insnAssignments.size();
@@ -236,8 +236,8 @@
* Helper method, to get the starts for a index, throwing the
* right exception for range problems.
*
- * @param index >= 0; the block index
- * @return null-ok; associated register set or <code>null</code> if there
+ * @param index {@code >= 0;} the block index
+ * @return {@code null-ok;} associated register set or {@code null} if there
* is none
*/
private RegisterSpecSet getStarts0(int index) {
diff --git a/dx/src/com/android/dx/ssa/MoveParamCombiner.java b/dx/src/com/android/dx/ssa/MoveParamCombiner.java
index a27aec5..352e3e6 100644
--- a/dx/src/com/android/dx/ssa/MoveParamCombiner.java
+++ b/dx/src/com/android/dx/ssa/MoveParamCombiner.java
@@ -143,8 +143,8 @@
* Returns the parameter index associated with a move-param insn. Does
* not verify that the insn is a move-param insn.
*
- * @param insn non-null; a move-param insn
- * @return >=0 parameter index
+ * @param insn {@code non-null;} a move-param insn
+ * @return {@code >=0;} parameter index
*/
private int getParamIndex(NormalSsaInsn insn) {
CstInsn cstInsn = (CstInsn)(insn.getOriginalRopInsn());
diff --git a/dx/src/com/android/dx/ssa/NormalSsaInsn.java b/dx/src/com/android/dx/ssa/NormalSsaInsn.java
index ad9315a..d3392ca 100644
--- a/dx/src/com/android/dx/ssa/NormalSsaInsn.java
+++ b/dx/src/com/android/dx/ssa/NormalSsaInsn.java
@@ -19,13 +19,10 @@
import com.android.dx.rop.code.*;
/**
- * A "normal" (non-phi) instruction in SSA form. Always wraps a ROP insn.
+ * A "normal" (non-phi) instruction in SSA form. Always wraps a rop insn.
*/
public final class NormalSsaInsn extends SsaInsn implements Cloneable {
-
- /**
- * ROP insn that we're wrapping
- */
+ /** {@code non-null;} rop insn that we're wrapping */
private Insn insn;
/**
@@ -35,21 +32,19 @@
* @param block block that contains this insn
*/
NormalSsaInsn(final Insn insn, final SsaBasicBlock block) {
- super(block);
+ super(insn.getResult(), block);
this.insn = insn;
- this.result = insn.getResult();
}
/** {@inheritDoc} */
@Override
public final void mapSourceRegisters(RegisterMapper mapper) {
-
RegisterSpecList oldSources = insn.getSources();
RegisterSpecList newSources = mapper.map(oldSources);
if (newSources != oldSources) {
- insn = insn.withNewRegisters(result, newSources);
- block.getParent().onSourcesChanged(this, oldSources);
+ insn = insn.withNewRegisters(getResult(), newSources);
+ getBlock().getParent().onSourcesChanged(this, oldSources);
}
}
@@ -57,7 +52,7 @@
* Changes one of the insn's sources. New source should be of same type
* and category.
*
- * @param index >=0; index of source to change
+ * @param index {@code >=0;} index of source to change
* @param newSpec spec for new source
*/
public final void changeOneSource(int index, RegisterSpec newSpec) {
@@ -68,6 +63,7 @@
for (int i = 0; i < sz; i++) {
newSources.set(i, i == index ? newSpec : origSources.get(i));
}
+
newSources.setImmutable();
RegisterSpec origSpec = origSources.get(index);
@@ -76,10 +72,10 @@
* If the register remains unchanged, we're only changing
* the type or local var name so don't update use list
*/
- block.getParent().onSourceChanged(this, origSpec, newSpec);
+ getBlock().getParent().onSourceChanged(this, origSpec, newSpec);
}
- insn = insn.withNewRegisters(result, newSources);
+ insn = insn.withNewRegisters(getResult(), newSources);
}
/**
@@ -90,22 +86,24 @@
*/
public final void setNewSources (RegisterSpecList newSources) {
RegisterSpecList origSources = insn.getSources();
+
if (origSources.size() != newSources.size()) {
throw new RuntimeException("Sources counts don't match");
}
- insn = insn.withNewRegisters(result, newSources);
+ insn = insn.withNewRegisters(getResult(), newSources);
}
/** {@inheritDoc} */
@Override
public NormalSsaInsn clone() {
- return (NormalSsaInsn)super.clone();
+ return (NormalSsaInsn) super.clone();
}
/**
- * Like rop.Insn.getSources()
- * @return null-ok; sources list
+ * Like rop.Insn.getSources().
+ *
+ * @return {@code null-ok;} sources list
*/
public RegisterSpecList getSources() {
return insn.getSources();
@@ -119,7 +117,7 @@
/** {@inheritDoc} */
@Override
public Insn toRopInsn() {
- return insn.withNewRegisters(result,insn.getSources());
+ return insn.withNewRegisters(getResult(), insn.getSources());
}
/**
@@ -143,7 +141,7 @@
if (insn.getOpcode().getOpcode() == RegOps.MARK_LOCAL) {
assignment = insn.getSources().get(0);
} else {
- assignment = result;
+ assignment = getResult();
}
if (assignment == null) {
@@ -167,8 +165,9 @@
*/
public void upgradeToLiteral() {
RegisterSpecList oldSources = insn.getSources();
+
insn = insn.withLastSourceLiteral();
- block.getParent().onSourcesChanged(this, oldSources);
+ getBlock().getParent().onSourcesChanged(this, oldSources);
}
/**
@@ -210,7 +209,7 @@
/**
* {@inheritDoc}
*
- * TODO increase the scope of this.
+ * TODO: Increase the scope of this.
*/
@Override
public boolean hasSideEffect() {
@@ -221,7 +220,7 @@
}
boolean hasLocalSideEffect
- = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
+ = Optimizer.getPreserveLocals() && getLocalAssignment() != null;
switch (opcode.getOpcode()) {
case RegOps.MOVE_RESULT:
diff --git a/dx/src/com/android/dx/ssa/Optimizer.java b/dx/src/com/android/dx/ssa/Optimizer.java
index cee6d7b..c5f6dc9 100644
--- a/dx/src/com/android/dx/ssa/Optimizer.java
+++ b/dx/src/com/android/dx/ssa/Optimizer.java
@@ -48,7 +48,7 @@
}
/**
- * @return non-null; translation advice
+ * @return {@code non-null;} translation advice
*/
public static TranslationAdvice getAdvice() {
return advice;
@@ -64,7 +64,7 @@
* @param isStatic true if this method has no 'this' pointer argument.
* @param inPreserveLocals true if local variable info should be preserved,
* at the cost of some registers and insns
- * @param inAdvice non-null; translation advice
+ * @param inAdvice {@code non-null;} translation advice
* @return optimized method
*/
public static RopMethod optimize(RopMethod rmeth, int paramWidth,
@@ -85,7 +85,7 @@
* @param isStatic true if this method has no 'this' pointer argument.
* @param inPreserveLocals true if local variable info should be preserved,
* at the cost of some registers and insns
- * @param inAdvice non-null; translation advice
+ * @param inAdvice {@code non-null;} translation advice
* @param steps set of optional optimization steps to run
* @return optimized method
*/
diff --git a/dx/src/com/android/dx/ssa/PhiInsn.java b/dx/src/com/android/dx/ssa/PhiInsn.java
index 1829133..64e85ac 100644
--- a/dx/src/com/android/dx/ssa/PhiInsn.java
+++ b/dx/src/com/android/dx/ssa/PhiInsn.java
@@ -30,67 +30,53 @@
* conversion back to ROP form.
*/
public final class PhiInsn extends SsaInsn {
+ /**
+ * result register. The original result register of the phi insn
+ * is needed during the renaming process after the new result
+ * register has already been chosen.
+ */
+ private final int ropResultReg;
/**
- * the original result register of the phi insn is needed during the
- * renaming process after the new result register has already been chosen.
+ * {@code non-null;} operands of the instruction; built up by
+ * {@link #addPhiOperand}
*/
- private int ropResultReg;
- private ArrayList<Operand> operands = new ArrayList<Operand>();
+ private final ArrayList<Operand> operands = new ArrayList<Operand>();
+
+ /** {@code null-ok;} source registers; constructed lazily */
private RegisterSpecList sources;
/**
- * A single phi operand, consiting of source register and block index
- * for move.
- */
- class Operand {
- RegisterSpec regSpec;
- int blockIndex;
- int ropLabel; //mostly for debugging
-
- Operand (final RegisterSpec regSpec, final int blockIndex,
- final int ropLabel){
- this.regSpec = regSpec;
- this.blockIndex = blockIndex;
- this.ropLabel = ropLabel;
- }
- }
-
- public static interface Visitor {
- public void visitPhiInsn(PhiInsn insn);
- }
-
- public PhiInsn clone() {
- throw new UnsupportedOperationException("can't clone phi");
- }
-
- /**
* Constructs a new phi insn with no operands.
+ *
* @param resultReg the result reg for this phi insn
* @param block block containing this insn.
*/
- PhiInsn(final RegisterSpec resultReg, final SsaBasicBlock block) {
- super(block);
- this.result = resultReg;
+ public PhiInsn(RegisterSpec resultReg, SsaBasicBlock block) {
+ super(resultReg, block);
ropResultReg = resultReg.getReg();
}
/**
* Makes a phi insn with a void result type.
+ *
* @param resultReg the result register for this phi insn.
* @param block block containing this insn.
*/
- PhiInsn(final int resultReg, final SsaBasicBlock block) {
- super(block);
-
+ public PhiInsn(final int resultReg, final SsaBasicBlock block) {
/*
- * The type here is bogus: the type depends on the operand and
- * will be derived later.
+ * The result type here is bogus: The type depends on the
+ * operand and will be derived later.
*/
- this.result = RegisterSpec.make(resultReg, Type.VOID);
+ super(RegisterSpec.make(resultReg, Type.VOID), block);
ropResultReg = resultReg;
}
+ /** {@inheritDoc} */
+ public PhiInsn clone() {
+ throw new UnsupportedOperationException("can't clone phi");
+ }
+
/**
* Updates the TypeBearers of all the sources (phi operands) to be
* the current TypeBearer of the register-defining instruction's result.
@@ -100,9 +86,8 @@
*
* @param ssaMeth method that contains this insn
*/
- void updateSourcesToDefinitions(SsaMethod ssaMeth) {
-
- for (Operand o: operands) {
+ public void updateSourcesToDefinitions(SsaMethod ssaMeth) {
+ for (Operand o : operands) {
RegisterSpec def
= ssaMeth.getDefinitionForRegister(
o.regSpec.getReg()).getResult();
@@ -116,37 +101,42 @@
/**
* Changes the result type. Used during phi type resolution
*
- * @param type non-null; new TypeBearer
- * @param local null-ok; new local info, if available
+ * @param type {@code non-null;} new TypeBearer
+ * @param local {@code null-ok;} new local info, if available
*/
- void changeResultType(TypeBearer type, LocalItem local) {
- result = RegisterSpec.makeLocalOptional(result.getReg(), type, local);
+ public void changeResultType(TypeBearer type, LocalItem local) {
+ setResult(RegisterSpec.makeLocalOptional(
+ getResult().getReg(), type, local));
}
/**
- * @return the original rop-form result reg. Useful during renaming.
+ * Gets the original rop-form result reg. This is useful during renaming.
+ *
+ * @return the original rop-form result reg
*/
- int getRopResultReg() {
+ public int getRopResultReg() {
return ropResultReg;
}
/**
- * Add an operand to this phi instruction
+ * 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
+ * @param predBlock predecessor block to be associated with this operand
*/
public void addPhiOperand(RegisterSpec registerSpec,
SsaBasicBlock predBlock) {
operands.add(new Operand(registerSpec, predBlock.getIndex(),
predBlock.getRopLabel()));
- // in case someone has already called getSources()
+ // Un-cache sources, in case someone has already called getSources().
sources = null;
}
/**
* 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
*/
@@ -157,7 +147,7 @@
/**
* {@inheritDoc}
*
- * Always returns null for <code>PhiInsn</code>s
+ * Always returns null for {@code PhiInsn}s.
*/
@Override
public Rop getOpcode() {
@@ -167,18 +157,17 @@
/**
* {@inheritDoc}
*
- * Always returns null for <code>PhiInsn</code>s
+ * Always returns null for {@code PhiInsn}s.
*/
@Override
public Insn getOriginalRopInsn() {
return null;
}
-
/**
* {@inheritDoc}
*
- * Always returns false for <code>PhiInsn</code>s
+ * Always returns false for {@code PhiInsn}s.
*/
@Override
public boolean canThrow() {
@@ -188,10 +177,10 @@
/**
* Gets sources. Constructed lazily from phi operand data structures and
* then cached.
- * @return sources list
+ *
+ * @return {@code non-null;} sources list
*/
public RegisterSpecList getSources() {
-
if (sources != null) {
return sources;
}
@@ -219,10 +208,10 @@
public boolean isRegASource(int reg) {
/*
* Avoid creating a sources list in case it has not already been
- * created
+ * created.
*/
- for (Operand o: operands) {
+ for (Operand o : operands) {
if (o.regSpec.getReg() == reg) {
return true;
}
@@ -236,12 +225,12 @@
*/
public boolean areAllOperandsEqual() {
if (operands.size() == 0 ) {
- // this should never happen
+ // This should never happen.
return true;
}
int firstReg = operands.get(0).regSpec.getReg();
- for (Operand o: operands) {
+ for (Operand o : operands) {
if (firstReg != o.regSpec.getReg()) {
return false;
}
@@ -253,19 +242,20 @@
/** {@inheritDoc} */
@Override
public final void mapSourceRegisters(RegisterMapper mapper) {
- for (Operand o: operands) {
+ for (Operand o : operands) {
RegisterSpec old = o.regSpec;
o.regSpec = mapper.map(old);
if (old != o.regSpec) {
- block.getParent().onSourceChanged(this, old, o.regSpec);
+ getBlock().getParent().onSourceChanged(this, old, o.regSpec);
}
}
sources = null;
}
/**
- * Always throws an exeption, since
- * a phi insn may not be converted back to rop form
+ * Always throws an exeption, since a phi insn may not be
+ * converted back to rop form.
+ *
* @return always throws exception
*/
@Override
@@ -276,17 +266,16 @@
/**
* Returns the list of predecessor blocks associated with all operands
- * that have <code>reg</code> as an operand register.
+ * that have {@code reg} as an operand register.
*
* @param reg register to look up
* @param ssaMeth method we're operating on
- * @return List of predecessor blocks, empty if none
+ * @return list of predecessor blocks, empty if none
*/
- public List<SsaBasicBlock> predBlocksForReg (int reg, SsaMethod ssaMeth) {
- ArrayList<SsaBasicBlock> ret
- = (ArrayList<SsaBasicBlock>)new ArrayList();
+ public List<SsaBasicBlock> predBlocksForReg(int reg, SsaMethod ssaMeth) {
+ ArrayList<SsaBasicBlock> ret = new ArrayList<SsaBasicBlock>();
- for (Operand o: operands) {
+ for (Operand o : operands) {
if (o.regSpec.getReg() == reg) {
ret.add(ssaMeth.getBlocks().get(o.blockIndex));
}
@@ -297,12 +286,13 @@
/** {@inheritDoc} */
@Override
- public boolean isPhiOrMove() {
+ public boolean isPhiOrMove() {
return true;
}
/** {@inheritDoc} */
- @Override public boolean hasSideEffect() {
+ @Override
+ public boolean hasSideEffect() {
return Optimizer.getPreserveLocals() && getLocalAssignment() != null;
}
@@ -312,25 +302,23 @@
v.visitPhiInsn(this);
}
- /**
- * @return human-readable string for listing dumps
- */
+ /** {@inheritDoc} */
public String toHuman() {
return toHumanWithInline(null);
}
/**
- * Returns human-readable string for listing dumps.
- * Allows sub-classes to specify extra text
- * @param extra null-ok; the argument to print after the opcode
+ * 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
*/
protected final String toHumanWithInline(String extra) {
StringBuffer sb = new StringBuffer(80);
sb.append(SourcePosition.NO_INFO);
- sb.append(": ");
- sb.append("phi");
+ sb.append(": phi");
if (extra != null) {
sb.append("(");
@@ -338,6 +326,8 @@
sb.append(")");
}
+ RegisterSpec result = getResult();
+
if (result == null) {
sb.append(" .");
} else {
@@ -361,4 +351,27 @@
return sb.toString();
}
+
+ /**
+ * A single phi operand, consiting of source register and block index
+ * for move.
+ */
+ private static class Operand {
+ public RegisterSpec regSpec;
+ public final int blockIndex;
+ public final int ropLabel; // only used for debugging
+
+ public Operand(RegisterSpec regSpec, int blockIndex, int ropLabel) {
+ this.regSpec = regSpec;
+ this.blockIndex = blockIndex;
+ this.ropLabel = ropLabel;
+ }
+ }
+
+ /**
+ * Visitor interface for instances of this (outer) class.
+ */
+ public static interface Visitor {
+ public void visitPhiInsn(PhiInsn insn);
+ }
}
diff --git a/dx/src/com/android/dx/ssa/RegisterMapper.java b/dx/src/com/android/dx/ssa/RegisterMapper.java
index 98503e2..1f45b42 100644
--- a/dx/src/com/android/dx/ssa/RegisterMapper.java
+++ b/dx/src/com/android/dx/ssa/RegisterMapper.java
@@ -21,13 +21,12 @@
import com.android.dx.util.ToHuman;
/**
- * 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.
+ * 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.
*/
public abstract class RegisterMapper {
-
/**
* Gets the count of registers (really, the total register width, since
* category width is counted) in the new namespace.
@@ -47,17 +46,16 @@
* @return new mapped register list, or old if nothing has changed.
*/
public final RegisterSpecList map(RegisterSpecList sources) {
- RegisterSpecList newSources;
-
- newSources = new RegisterSpecList(sources.size());
-
int sz = sources.size();
+ RegisterSpecList newSources = new RegisterSpecList(sz);
+
for (int i = 0; i < sz; i++) {
newSources.set(i, map(sources.get(i)));
}
newSources.setImmutable();
- // Return the old sources if nothing has changed
- return newSources.equals(sources)? sources: newSources;
+
+ // Return the old sources if nothing has changed.
+ return newSources.equals(sources) ? sources : newSources;
}
}
diff --git a/dx/src/com/android/dx/ssa/SCCP.java b/dx/src/com/android/dx/ssa/SCCP.java
index 1d95da6..73e9b49 100644
--- a/dx/src/com/android/dx/ssa/SCCP.java
+++ b/dx/src/com/android/dx/ssa/SCCP.java
@@ -102,11 +102,11 @@
*/
private void addUsersToWorklist(int reg, int latticeValue) {
if (latticeValue == VARYING) {
- for (SsaInsn insn: ssaMeth.getUseListForRegister(reg)) {
+ for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
varyingWorklist.add(insn);
}
} else {
- for (SsaInsn insn: ssaMeth.getUseListForRegister(reg)) {
+ for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
ssaWorklist.add(insn);
}
}
@@ -137,9 +137,6 @@
}
}
- private boolean setLatticeValueTo(int reg, int value) {
- return setLatticeValueTo(reg, value, null);
- }
/**
* Simulates a PHI node and set the lattice for the result
* to the approriate value.
@@ -160,6 +157,7 @@
int phiResultValue = TOP;
Constant phiConstant = null;
int sourceSize = sources.size();
+
for (int i = 0; i < sourceSize; i++) {
int predBlockIndex = insn.predBlockIndexForSourcesIndex(i);
int sourceReg = sources.get(i).getReg();
@@ -194,7 +192,7 @@
* @param block Block to visit
*/
private void simulateBlock(SsaBasicBlock block) {
- for (SsaInsn insn: block.getInsns()) {
+ for (SsaInsn insn : block.getInsns()) {
if (insn instanceof PhiInsn) {
simulatePhi((PhiInsn) insn);
} else {
@@ -464,7 +462,7 @@
* Update the sources RegisterSpec's of all non-move uses.
* These will be used in later steps.
*/
- for(SsaInsn insn: ssaMeth.getUseListForRegister(reg)) {
+ for (SsaInsn insn : ssaMeth.getUseListForRegister(reg)) {
if (insn.isPhiOrMove()) {
continue;
}
@@ -478,7 +476,6 @@
RegisterSpec newSpec
= spec.withType((TypedConstant)latticeConstants[reg]);
-
nInsn.changeOneSource(index, newSpec);
}
}
diff --git a/dx/src/com/android/dx/ssa/SetFactory.java b/dx/src/com/android/dx/ssa/SetFactory.java
index f34d08d..92e965f 100644
--- a/dx/src/com/android/dx/ssa/SetFactory.java
+++ b/dx/src/com/android/dx/ssa/SetFactory.java
@@ -59,8 +59,8 @@
/**
* Make IntSet for the dominance-frontier sets.
*
- * @param szBlocks >=0; count of basic blocks in method
- * @return non-null; appropriate set
+ * @param szBlocks {@code >=0;} count of basic blocks in method
+ * @return {@code non-null;} appropriate set
*/
/*package*/ static IntSet makeDomFrontSet(int szBlocks) {
return szBlocks <= DOMFRONT_SET_THRESHOLD_SIZE
@@ -72,8 +72,8 @@
* Make IntSet for the interference graph sets. Public because
* InterferenceGraph is in another package.
*
- * @param countRegs >=0; count of SSA registers used in method
- * @return non-null; appropriate set
+ * @param countRegs {@code >=0;} count of SSA registers used in method
+ * @return {@code non-null;} appropriate set
*/
public static IntSet makeInterferenceSet(int countRegs) {
return countRegs <= INTERFERENCE_SET_THRESHOLD_SIZE
@@ -84,8 +84,8 @@
/**
* Make IntSet for register live in/out sets.
*
- * @param countRegs >=0; count of SSA registers used in method
- * @return non-null; appropriate set
+ * @param countRegs {@code >=0;} count of SSA registers used in method
+ * @return {@code non-null;} appropriate set
*/
/*package*/ static IntSet makeLivenessSet(int countRegs) {
return countRegs <= LIVENESS_SET_THRESHOLD_SIZE
diff --git a/dx/src/com/android/dx/ssa/SsaBasicBlock.java b/dx/src/com/android/dx/ssa/SsaBasicBlock.java
index 99ada7e..ab0e122 100644
--- a/dx/src/com/android/dx/ssa/SsaBasicBlock.java
+++ b/dx/src/com/android/dx/ssa/SsaBasicBlock.java
@@ -36,53 +36,80 @@
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
/**
* An SSA representation of a basic block.
*/
public final class SsaBasicBlock {
-
- /** non-null; insn list associated with this instance */
- private ArrayList<SsaInsn> insns;
- /** non-null; predecessor set (by block list index) */
- private BitSet predecessors;
- /** non-null; successor set (by block list index) */
- private BitSet successors;
/**
- * non-null; ordered successor list
+ * {@code non-null;} comparator for instances of this class that
+ * just compares block labels
+ */
+ public static final Comparator<SsaBasicBlock> LABEL_COMPARATOR =
+ new LabelComparator();
+
+ /** {@code non-null;} insn list associated with this instance */
+ private ArrayList<SsaInsn> insns;
+
+ /** {@code non-null;} predecessor set (by block list index) */
+ private BitSet predecessors;
+
+ /** {@code non-null;} successor set (by block list index) */
+ private BitSet successors;
+
+ /**
+ * {@code non-null;} ordered successor list
* (same block may be listed more than once)
*/
private IntList successorList;
- /** block list index of primary successor, or -1 for no primary successor */
+
+ /**
+ * block list index of primary successor, or {@code -1} for no primary
+ * successor
+ */
private int primarySuccessor = -1;
+
/** label of block in rop form */
private int ropLabel;
- /** non-null; method we belong to */
+
+ /** {@code non-null;} method we belong to */
private SsaMethod parent;
+
/** our index into parent.getBlock() */
private int index;
+
/** list of dom children */
private final ArrayList<SsaBasicBlock> domChildren;
- /**
- * The number of moves added to the end of the block during the
+ /**
+ * the number of moves added to the end of the block during the
* phi-removal process. Retained for subsequent move scheduling.
*/
private int movesFromPhisAtEnd = 0;
- /**
- * The number of moves added to the beginning of the block during the
+
+ /**
+ * the number of moves added to the beginning of the block during the
* phi-removal process. Retained for subsequent move scheduling.
*/
private int movesFromPhisAtBeginning = 0;
- /** null-ok; indexed by reg: the regs that are live-in at this block */
+ /**
+ * {@code null-ok;} indexed by reg: the regs that are live-in at
+ * this block
+ */
private IntSet liveIn;
- /** null-ok; indexed by reg: the regs that are live-out at this block */
+
+ /**
+ * {@code null-ok;} indexed by reg: the regs that are live-out at
+ * this block
+ */
private IntSet liveOut;
/**
- * Create a new empty basic block
+ * Creates a new empty basic block.
+ *
* @param basicBlockIndex index this block will have
* @param ropLabel original rop-form label
* @param parent method of this block
@@ -106,26 +133,20 @@
*
* @param rmeth original method
* @param basicBlockIndex index this block will have
- * @param parent method of this block
- * predecessor set will be updated.
+ * @param parent method of this block predecessor set will be
+ * updated
* @return new instance
*/
public static SsaBasicBlock newFromRop(RopMethod rmeth,
int basicBlockIndex, final SsaMethod parent) {
-
- BasicBlockList ropBlocks;
- SsaBasicBlock result;
- InsnList ropInsns;
- BasicBlock bb;
-
- ropBlocks = rmeth.getBlocks();
- bb = ropBlocks.get(basicBlockIndex);
-
- result = new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent);
-
- ropInsns = bb.getInsns();
+ BasicBlockList ropBlocks = rmeth.getBlocks();
+ BasicBlock bb = ropBlocks.get(basicBlockIndex);
+ SsaBasicBlock result =
+ new SsaBasicBlock(basicBlockIndex, bb.getLabel(), parent);
+ InsnList ropInsns = bb.getInsns();
result.insns.ensureCapacity(ropInsns.size());
+
for (int i = 0, sz = ropInsns.size() ; i < sz ; i++) {
result.insns.add(new NormalSsaInsn (ropInsns.get(i), result));
}
@@ -141,7 +162,6 @@
= SsaMethod.indexListFromLabelList(ropBlocks,
bb.getSuccessors());
-
if (result.successorList.size() != 0) {
int primarySuccessor = bb.getPrimarySuccessor();
@@ -156,18 +176,18 @@
* Adds a basic block as a dom child for this block. Used when constructing
* the dom tree.
*
- * @param child non-null; new dom child
+ * @param child {@code non-null;} new dom child
*/
- void addDomChild(SsaBasicBlock child) {
+ public void addDomChild(SsaBasicBlock child) {
domChildren.add(child);
}
/**
* Gets the dom children for this node. Don't modify this list.
*
- * @return non-null; list of dom children
+ * @return {@code non-null;} list of dom children
*/
- ArrayList<SsaBasicBlock> getDomChildren() {
+ public ArrayList<SsaBasicBlock> getDomChildren() {
return domChildren;
}
@@ -175,9 +195,9 @@
* Adds a phi insn to the beginning of this block. The result type of
* the phi will be set to void, to indicate that it's currently unknown.
*
- * @param reg >=0 result reg
+ * @param reg {@code >=0;} result reg
*/
- void addPhiInsnForReg(int reg) {
+ public void addPhiInsnForReg(int reg) {
insns.add(0, new PhiInsn(reg, this));
}
@@ -186,9 +206,9 @@
* when the result type or local-association can be determined at phi
* insert time.
*
- * @param resultSpec non-null; reg
+ * @param resultSpec {@code non-null;} reg
*/
- void addPhiInsnForReg(RegisterSpec resultSpec) {
+ public void addPhiInsnForReg(RegisterSpec resultSpec) {
insns.add(0, new PhiInsn(resultSpec, this));
}
@@ -196,9 +216,9 @@
* Adds an insn to the head of this basic block, just after any phi
* insns.
*
- * @param insn non-null; rop-form insn to add
+ * @param insn {@code non-null;} rop-form insn to add
*/
- void addInsnToHead(Insn insn) {
+ public void addInsnToHead(Insn insn) {
SsaInsn newInsn = SsaInsn.makeFromRop(insn, this);
insns.add(getCountPhiInsns(), newInsn);
parent.onInsnAdded(newInsn);
@@ -208,9 +228,9 @@
* Replaces the last insn in this block. The provided insn must have
* some branchingness.
*
- * @param insn non-null; rop-form insn to add, which must branch.
+ * @param insn {@code non-null;} rop-form insn to add, which must branch.
*/
- void replaceLastInsn(Insn insn) {
+ public void replaceLastInsn(Insn insn) {
if (insn.getOpcode().getBranchingness() == Rop.BRANCH_NONE) {
throw new IllegalArgumentException("last insn must branch");
}
@@ -225,12 +245,13 @@
}
/**
- * Visits each phi insn
- * @param v callback
+ * Visits each phi insn.
+ *
+ * @param v {@code non-null;} the callback
*/
public void forEachPhiInsn(PhiInsn.Visitor v) {
-
int sz = insns.size();
+
for (int i = 0; i < sz; i++) {
SsaInsn insn = insns.get(i);
if (insn instanceof PhiInsn) {
@@ -251,7 +272,7 @@
public void removeAllPhiInsns() {
/*
* Presently we assume PhiInsn's are in a continuous
- * block at the top of the list
+ * block at the top of the list.
*/
insns.subList(0, getCountPhiInsns()).clear();
@@ -259,6 +280,7 @@
/**
* Gets the number of phi insns at the top of this basic block.
+ *
* @return count of phi insns
*/
private int getCountPhiInsns() {
@@ -276,15 +298,15 @@
}
/**
- * @return non-null;the (mutable) instruction list for this block,
- * with phi insns at the beginning.
+ * @return {@code non-null;} the (mutable) instruction list for this block,
+ * with phi insns at the beginning
*/
public ArrayList<SsaInsn> getInsns() {
return insns;
}
/**
- * @return non-null; the (mutable) list of phi insns for this block
+ * @return {@code non-null;} the (mutable) list of phi insns for this block
*/
public List<SsaInsn> getPhiInsns() {
return insns.subList(0, getCountPhiInsns());
@@ -312,29 +334,30 @@
}
/**
- * @return non-null;predecessors set, indexed by block index
+ * @return {@code non-null;} predecessors set, indexed by block index
*/
public BitSet getPredecessors() {
return predecessors;
}
/**
- * @return non-null;successors set, indexed by block index
+ * @return {@code non-null;} successors set, indexed by block index
*/
public BitSet getSuccessors() {
return successors;
}
/**
- * @return non-null;ordered successor list, containing block indicies
+ * @return {@code non-null;} ordered successor list, containing block
+ * indicies
*/
public IntList getSuccessorList() {
return successorList;
}
/**
- * @return >= -1; block index of primary successor or -1 if no
- * primary successor.
+ * @return {@code >= -1;} block index of primary successor or
+ * {@code -1} if no primary successor
*/
public int getPrimarySuccessorIndex() {
return primarySuccessor;
@@ -348,7 +371,8 @@
}
/**
- * @return null-ok; the primary successor block or null if there is none.
+ * @return {@code null-ok;} the primary successor block or {@code null}
+ * if there is none
*/
public SsaBasicBlock getPrimarySuccessor() {
if (primarySuccessor < 0) {
@@ -373,7 +397,7 @@
}
/**
- * @return non-null; method that contains this block
+ * @return {@code non-null;} method that contains this block
*/
public SsaMethod getParent() {
return parent;
@@ -383,23 +407,23 @@
* Inserts a new empty GOTO block as a predecessor to this block.
* All previous predecessors will be predecessors to the new block.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public SsaBasicBlock insertNewPredecessor() {
SsaBasicBlock newPred = parent.makeNewGotoBlock();
- // Update the new block
+ // Update the new block.
newPred.predecessors = predecessors;
newPred.successors.set(index) ;
newPred.successorList.add(index);
newPred.primarySuccessor = index;
- // Update us
+ // Update us.
predecessors = new BitSet(parent.getBlocks().size());
predecessors.set(newPred.index);
- // Update our (soon-to-be) old predecessors
+ // Update our (soon-to-be) old predecessors.
for (int i = newPred.predecessors.nextSetBit(0); i >= 0;
i = newPred.predecessors.nextSetBit(i + 1)) {
@@ -412,15 +436,15 @@
}
/**
- * Constructs and inserts a new empty GOTO block <code>Z</code> between
- * this block (<code>A</code>) and a current successor block
- * (<code>B</code>). The new block will replace B as A's successor and
+ * Constructs and inserts a new empty GOTO block {@code Z} between
+ * this block ({@code A}) and a current successor block
+ * ({@code B}). The new block will replace B as A's successor and
* A as B's predecessor. A and B will no longer be directly connected.
* If B is listed as a successor multiple times, all references
* are replaced.
*
* @param other current successor (B)
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public SsaBasicBlock insertNewSuccessor(SsaBasicBlock other) {
SsaBasicBlock newSucc = parent.makeNewGotoBlock();
@@ -430,15 +454,15 @@
+ " not successor of " + getRopLabelString());
}
- // Update the new block
+ // Update the new block.
newSucc.predecessors.set(this.index);
newSucc.successors.set(other.index) ;
newSucc.successorList.add(other.index);
newSucc.primarySuccessor = other.index;
- // Update us
+ // Update us.
for (int i = successorList.size() - 1 ; i >= 0; i--) {
- if(successorList.get(i) == other.index) {
+ if (successorList.get(i) == other.index) {
successorList.set(i, newSucc.index);
}
}
@@ -449,7 +473,7 @@
successors.clear(other.index);
successors.set(newSucc.index);
- // Update "other"
+ // Update "other".
other.predecessors.set(newSucc.index);
other.predecessors.set(index, successors.get(other.index));
@@ -457,17 +481,18 @@
}
/**
- * Replace an old successor with a new successor.
- * Throws RuntimeException if oldIndex was not a successor.
+ * Replaces an old successor with a new successor. This will throw
+ * RuntimeException if {@code oldIndex} was not a successor.
+ *
* @param oldIndex index of old successor block
- * @param newIndex index of new successor block.
+ * @param newIndex index of new successor block
*/
public void replaceSuccessor(int oldIndex, int newIndex) {
if (oldIndex == newIndex) {
return;
}
- // Update us
+ // Update us.
successors.set(newIndex);
if (primarySuccessor == oldIndex) {
@@ -475,17 +500,17 @@
}
for (int i = successorList.size() - 1 ; i >= 0; i--) {
- if(successorList.get(i) == oldIndex) {
+ if (successorList.get(i) == oldIndex) {
successorList.set(i, newIndex);
}
}
successors.clear(oldIndex);
- // Update new successor
+ // Update new successor.
parent.getBlocks().get(newIndex).predecessors.set(index);
- // Update old successor
+ // Update old successor.
parent.getBlocks().get(oldIndex).predecessors.clear(index);
}
@@ -495,7 +520,7 @@
* is not an exit predecessor or is the exit block, this block does
* nothing. For use by {@link com.android.dx.ssa.SsaMethod#makeExitBlock}
*
- * @param exitBlock non-null; exit block
+ * @param exitBlock {@code non-null;} exit block
*/
public void exitBlockFixup(SsaBasicBlock exitBlock) {
if (this == exitBlock) {
@@ -519,6 +544,7 @@
* before the last instruction. If the result of the final instruction
* is the source in question, then the move is placed at the beginning of
* the primary successor block. This is for unversioned registers.
+ *
* @param result move destination
* @param source move source
*/
@@ -538,12 +564,13 @@
if (lastInsn.getResult() != null || lastInsn.getSources().size() > 0) {
/*
- * The final insn in this block has a source or result register,
- * and the moves we may need to place and schedule may interfere.
- * We need to insert this instruction at the
- * beginning of the primary successor block instead. We know
- * this is safe, because when we edge-split earlier, we ensured
- * that each successor has only us as a predecessor.
+ * The final insn in this block has a source or result
+ * register, and the moves we may need to place and
+ * schedule may interfere. We need to insert this
+ * instruction at the beginning of the primary successor
+ * block instead. We know this is safe, because when we
+ * edge-split earlier, we ensured that each successor has
+ * only us as a predecessor.
*/
for (int i = successors.nextSetBit(0)
@@ -557,19 +584,14 @@
}
} else {
/*
- * We can safely add a move to the end of the block
- * just before the last instruction because
- * the final insn does not assign to anything.
+ * We can safely add a move to the end of the block just
+ * before the last instruction, because the final insn does
+ * not assign to anything.
*/
-
- RegisterSpecList sources;
- sources = RegisterSpecList.make(source);
-
- NormalSsaInsn toAdd;
-
- toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO, result, sources), this);
+ RegisterSpecList sources = RegisterSpecList.make(source);
+ NormalSsaInsn toAdd = new NormalSsaInsn(
+ new PlainInsn(Rops.opMove(result.getType()),
+ SourcePosition.NO_INFO, result, sources), this);
insns.add(insns.size() - 1, toAdd);
@@ -578,28 +600,24 @@
}
/**
- * Add a move instruction after the phi insn block.
+ * Adds a move instruction after the phi insn block.
+ *
* @param result move destination
* @param source move source
*/
public void addMoveToBeginning (RegisterSpec result, RegisterSpec source) {
-
if (result.getReg() == source.getReg()) {
// Sometimes we end up with no-op moves. Ignore them here.
return;
}
- RegisterSpecList sources;
- sources = RegisterSpecList.make(source);
-
- NormalSsaInsn toAdd;
-
- toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO, result, sources), this);
+ RegisterSpecList sources = RegisterSpecList.make(source);
+ NormalSsaInsn toAdd = new NormalSsaInsn(
+ new PlainInsn(Rops.opMove(result.getType()),
+ SourcePosition.NO_INFO, result, sources), this);
insns.add(getCountPhiInsns(), toAdd);
- movesFromPhisAtBeginning++;
+ movesFromPhisAtBeginning++;
}
/**
@@ -612,7 +630,7 @@
private static void setRegsUsed (BitSet regsUsed, RegisterSpec rs) {
regsUsed.set(rs.getReg());
if (rs.getCategory() > 1) {
- regsUsed.set(rs.getReg() + 1);
+ regsUsed.set(rs.getReg() + 1);
}
}
@@ -638,14 +656,16 @@
* reads of any register happen before writes to that register.
* NOTE: caller is expected to returnSpareRegisters()!
*
- * TODO See Briggs, et al "Practical Improvements to the Construction and
+ * TODO: See Briggs, et al "Practical Improvements to the Construction and
* Destruction of Static Single Assignment Form" section 5. a) This can
* be done in three passes.
+ *
* @param toSchedule List of instructions. Must consist only of moves.
*/
private void scheduleUseBeforeAssigned(List<SsaInsn> toSchedule) {
BitSet regsUsedAsSources = new BitSet(parent.getRegCount());
- // TODO get rid of this
+
+ // TODO: Get rid of this.
BitSet regsUsedAsResults = new BitSet(parent.getRegCount());
int sz = toSchedule.size();
@@ -680,8 +700,10 @@
}
}
- // If we've made no progress in this iteration, there's a
- // circular dependency. Split it using the temp reg.
+ /*
+ * If we've made no progress in this iteration, there's a
+ * circular dependency. Split it using the temp reg.
+ */
if (oldInsertPlace == insertPlace) {
SsaInsn insnToSplit = null;
@@ -694,43 +716,40 @@
insn.getSources().get(0))) {
insnToSplit = insn;
- // We're going to split this insn--move it to the
- // front
+ /*
+ * We're going to split this insn; move it to the
+ * front.
+ */
Collections.swap(toSchedule, insertPlace, i);
break;
}
}
- // At least one insn will be set above
+ // At least one insn will be set above.
RegisterSpec result = insnToSplit.getResult();
RegisterSpec tempSpec = result.withReg(
parent.borrowSpareRegister(result.getCategory()));
- NormalSsaInsn toAdd;
-
- toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO,
- tempSpec,
- insnToSplit.getSources()), this);
+ NormalSsaInsn toAdd = new NormalSsaInsn(
+ new PlainInsn(Rops.opMove(result.getType()),
+ SourcePosition.NO_INFO,
+ tempSpec,
+ insnToSplit.getSources()), this);
toSchedule.add(insertPlace++, toAdd);
- NormalSsaInsn toReplace;
- RegisterSpecList newSources;
+ RegisterSpecList newSources = RegisterSpecList.make(tempSpec);
- newSources = RegisterSpecList.make(tempSpec);
-
- toReplace = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(result.getType()),
- SourcePosition.NO_INFO,
- result,
- newSources), this);
+ NormalSsaInsn toReplace = new NormalSsaInsn(
+ new PlainInsn(Rops.opMove(result.getType()),
+ SourcePosition.NO_INFO,
+ result,
+ newSources), this);
toSchedule.set(insertPlace, toReplace);
- // size has changed
+ // The size changed.
sz = toSchedule.size();
}
@@ -740,12 +759,12 @@
}
/**
- * Adds regV to the live-out list for this block.
- * Called by the liveness analyzer.
+ * Adds {@code regV} to the live-out list for this block. This is called
+ * by the liveness analyzer.
+ *
* @param regV register that is live-out for this block.
*/
- public void
- addLiveOut (int regV) {
+ public void addLiveOut (int regV) {
if (liveOut == null) {
liveOut = SetFactory.makeLivenessSet(parent.getRegCount());
}
@@ -754,24 +773,24 @@
}
/**
- * Adds regV to the live-in list for this block.
- * Called by the liveness analyzer.
+ * Adds {@code regV} to the live-in list for this block. This is
+ * called by the liveness analyzer.
+ *
* @param regV register that is live-in for this block.
*/
- public void
- addLiveIn (int regV) {
+ public void addLiveIn (int regV) {
if (liveIn == null) {
liveIn = SetFactory.makeLivenessSet(parent.getRegCount());
}
- liveIn.add(regV);
+ liveIn.add(regV);
}
/**
* Returns the set of live-in registers. Valid after register
* interference graph has been generated, otherwise empty.
*
- * @return non-null; live-in register set.
+ * @return {@code non-null;} live-in register set.
*/
public IntSet getLiveInRegs() {
if (liveIn == null) {
@@ -783,8 +802,8 @@
/**
* Returns the set of live-out registers. Valid after register
* interference graph has been generated, otherwise empty.
- *
- * @return non-null; live-out register set.
+ *
+ * @return {@code non-null;} live-out register set
*/
public IntSet getLiveOutRegs() {
if (liveOut == null) {
@@ -806,15 +825,15 @@
* that it's either the start block or it has predecessors, which suffices
* for all current control flow transformations.
*
- * @return true if reachable
+ * @return {@code true} if reachable
*/
public boolean isReachable() {
return index == parent.getEntryBlockIndex()
|| predecessors.cardinality() > 0;
}
-
+
/**
- * Sorts move instructions added via <code>addMoveToEnd</code> during
+ * Sorts move instructions added via {@code addMoveToEnd} during
* phi removal so that results don't overwrite sources that are used.
* For use after all phis have been removed and all calls to
* addMoveToEnd() have been made.<p>
@@ -825,7 +844,6 @@
* refers value before any other phis have executed.
*/
public void scheduleMovesFromPhis() {
-
if (movesFromPhisAtBeginning > 1) {
List<SsaInsn> toSchedule;
@@ -835,32 +853,37 @@
SsaInsn firstNonPhiMoveInsn = insns.get(movesFromPhisAtBeginning);
- //TODO it's actually possible that this case never happens,
- //because a move-exception block, having only one predecessor
- //in SSA form, perhaps is never on a dominance frontier.
+ /*
+ * TODO: It's actually possible that this case never happens,
+ * because a move-exception block, having only one predecessor
+ * in SSA form, perhaps is never on a dominance frontier.
+ */
if (firstNonPhiMoveInsn.isMoveException()) {
if (true) {
/*
* We've yet to observe this case, and if it can
- * occur the code written to handle it probably
+ * occur the code written to handle it probably
* does not work.
*/
throw new RuntimeException(
"Unexpected: moves from "
+"phis before move-exception");
} else {
-
- // A move-exception insn must be placed first in this block
- // We need to move it there, and deal with possible
- // interference.
+ /*
+ * A move-exception insn must be placed first in this block
+ * We need to move it there, and deal with possible
+ * interference.
+ */
boolean moveExceptionInterferes = false;
int moveExceptionResult
= firstNonPhiMoveInsn.getResult().getReg();
- // Does the move-exception result reg interfere with the
- // phi moves?
- for(SsaInsn insn: toSchedule) {
+ /*
+ * Does the move-exception result reg interfere with the
+ * phi moves?
+ */
+ for (SsaInsn insn : toSchedule) {
if (insn.isResultReg(moveExceptionResult)
|| insn.isRegASource(moveExceptionResult)) {
moveExceptionInterferes = true;
@@ -869,81 +892,107 @@
}
if (!moveExceptionInterferes) {
- // The easy case
+ // This is the easy case.
insns.remove(movesFromPhisAtBeginning);
insns.add(0, firstNonPhiMoveInsn);
} else {
- // We need to move the result to a spare reg and move it
- // back.
-
- int spareRegister;
- RegisterSpec originalResultSpec;
-
- originalResultSpec = firstNonPhiMoveInsn.getResult();
- spareRegister = parent.borrowSpareRegister(
+ /*
+ * We need to move the result to a spare reg
+ * and move it back.
+ */
+ RegisterSpec originalResultSpec
+ = firstNonPhiMoveInsn.getResult();
+ int spareRegister = parent.borrowSpareRegister(
originalResultSpec.getCategory());
- // We now move it to a spare register
+ // We now move it to a spare register.
firstNonPhiMoveInsn.changeResultReg(spareRegister);
- RegisterSpec tempSpec = firstNonPhiMoveInsn.getResult();
+ RegisterSpec tempSpec =
+ firstNonPhiMoveInsn.getResult();
insns.add(0, firstNonPhiMoveInsn);
- // And here we move it back
+ // And here we move it back.
- NormalSsaInsn toAdd;
-
- toAdd = new NormalSsaInsn(
- new PlainInsn(Rops.opMove(
- tempSpec.getType()),
- SourcePosition.NO_INFO,
- originalResultSpec,
- RegisterSpecList.make(tempSpec)),
+ NormalSsaInsn toAdd = new NormalSsaInsn(
+ new PlainInsn(
+ Rops.opMove(tempSpec.getType()),
+ SourcePosition.NO_INFO,
+ originalResultSpec,
+ RegisterSpecList.make(tempSpec)),
this);
- // Place it immediately after the phi-moves,
- // overwriting the move-exception that was there.
+ /*
+ * Place it immediately after the phi-moves,
+ * overwriting the move-exception that was there.
+ */
insns.set(movesFromPhisAtBeginning + 1, toAdd);
}
}
}
}
+
if (movesFromPhisAtEnd > 1) {
scheduleUseBeforeAssigned(
insns.subList(insns.size() - movesFromPhisAtEnd - 1,
insns.size() - 1));
}
- // Return registers borrowed here and in scheduleUseBeforeAssigned()
+ // Return registers borrowed here and in scheduleUseBeforeAssigned().
parent.returnSpareRegisters();
}
/**
- * Visit all insns in this block
- * @param visitor callback interface
+ * Visits all insns in this block.
+ *
+ * @param visitor {@code non-null;} callback interface
*/
public void forEachInsn(SsaInsn.Visitor visitor) {
- for (SsaInsn insn: insns) {
- insn.accept(visitor);
+ // This gets called a LOT, and not using an iterator
+ // saves a lot of allocations and reduces memory usage
+ int len = insns.size();
+ for (int i = 0; i < len; i++) {
+ insns.get(i).accept(visitor);
}
}
+ /** {@inheritDoc} */
public String toString() {
return "{" + index + ":" + Hex.u2(ropLabel) + '}';
}
/**
- * Visitor interface for basic blocks
+ * Visitor interface for basic blocks.
*/
public interface Visitor {
-
/**
* Indicates a block has been visited by an iterator method.
- * @param v non-null; block visited
- * @param parent null-ok; parent node if applicable.
+ *
+ * @param v {@code non-null;} block visited
+ * @param parent {@code null-ok;} parent node if applicable
*/
void visitBlock (SsaBasicBlock v, SsaBasicBlock parent);
}
+
+ /**
+ * Label comparator.
+ */
+ public static final class LabelComparator
+ implements Comparator<SsaBasicBlock> {
+ /** {@inheritDoc} */
+ public int compare(SsaBasicBlock b1, SsaBasicBlock b2) {
+ int label1 = b1.ropLabel;
+ int label2 = b2.ropLabel;
+
+ if (label1 < label2) {
+ return -1;
+ } else if (label1 > label2) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
}
diff --git a/dx/src/com/android/dx/ssa/SsaConverter.java b/dx/src/com/android/dx/ssa/SsaConverter.java
index a731fcb..d5be287 100644
--- a/dx/src/com/android/dx/ssa/SsaConverter.java
+++ b/dx/src/com/android/dx/ssa/SsaConverter.java
@@ -27,22 +27,23 @@
* Converts ROP methods to SSA Methods
*/
public class SsaConverter {
- public static boolean DEBUG = false;
+ public static final boolean DEBUG = false;
/**
- * returns an SSA representation, edge-split and with phi functions placed
+ * Returns an SSA representation, edge-split and with phi
+ * functions placed.
+ *
* @param rmeth input
* @param paramWidth the total width, in register-units, of the method's
* parameters
- * @param isStatic true if this method has no 'this'
+ * @param isStatic {@code true} if this method has no {@code this}
* pointer argument
* @return output in SSA form
*/
- public static SsaMethod convertToSsaMethod(RopMethod rmeth,
+ public static SsaMethod convertToSsaMethod(RopMethod rmeth,
int paramWidth, boolean isStatic) {
- SsaMethod result;
-
- result = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
+ SsaMethod result
+ = SsaMethod.newFromRopMethod(rmeth, paramWidth, isStatic);
edgeSplit(result);
@@ -52,7 +53,7 @@
new SsaRenamer(result).run();
/*
- * Exit block, added here, is not considered for edge splitting
+ * The exit block, added here, is not considered for edge splitting
* or phi placement since no actual control flows to it.
*/
result.makeExitBlock();
@@ -62,10 +63,12 @@
/**
* Returns an SSA represention with only the edge-splitter run.
+ *
* @param rmeth method to process
* @param paramWidth width of all arguments in the method
- * @param isStatic true if this method has no 'this' pointer argument
- * @return an SSA represention with only the edge-splitter run.
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return an SSA represention with only the edge-splitter run
*/
public static SsaMethod testEdgeSplit (RopMethod rmeth, int paramWidth,
boolean isStatic) {
@@ -80,10 +83,12 @@
/**
* Returns an SSA represention with only the steps through the
* phi placement run.
+ *
* @param rmeth method to process
* @param paramWidth width of all arguments in the method
- * @param isStatic true if this method has no 'this' pointer argument
- * @return an SSA represention with only the edge-splitter run.
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ * @return an SSA represention with only the edge-splitter run
*/
public static SsaMethod testPhiPlacement (RopMethod rmeth, int paramWidth,
boolean isStatic) {
@@ -100,7 +105,8 @@
}
/**
- * See Appel section 19.1
+ * See Appel section 19.1:
+ *
* Converts CFG into "edge-split" form, such that each node either a
* unique successor or unique predecessor.<p>
*
@@ -109,11 +115,10 @@
* value to have a primary successor that has no other
* predecessor. This ensures move statements can always be
* inserted correctly when phi statements are removed.
- *
+ *
* @param result method to process
*/
private static void edgeSplit(SsaMethod result) {
-
edgeSplitPredecessors(result);
edgeSplitMoveExceptionsAndResults(result);
edgeSplitSuccessors(result);
@@ -122,13 +127,16 @@
/**
* Inserts Z nodes as new predecessors for every node that has multiple
* successors and multiple predecessors.
- * @param result non-null; method to process
+ *
+ * @param result {@code non-null;} method to process
*/
private static void edgeSplitPredecessors(SsaMethod result) {
ArrayList<SsaBasicBlock> blocks = result.getBlocks();
-
- // New blocks are added to the end of the block list during
- // this iteration
+
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
for (int i = blocks.size() - 1; i >= 0; i-- ) {
SsaBasicBlock block = blocks.get(i);
if (nodeNeedsUniquePredecessor(block)) {
@@ -138,12 +146,11 @@
}
/**
- * @param block non-null; block in question
- * @return true if this node needs to have a unique predecessor created for
- * it.
+ * @param block {@code non-null;} block in question
+ * @return {@code true} if this node needs to have a unique
+ * predecessor created for it
*/
private static boolean nodeNeedsUniquePredecessor(SsaBasicBlock block) {
-
/*
* Any block with that has both multiple successors and multiple
* predecessors needs a new predecessor node.
@@ -161,59 +168,68 @@
* We may need room to insert move insns later, so make sure to split
* any block that starts with a move-exception such that there is a
* unique move-exception block for each predecessor.
+ *
* @param ssaMeth method to process
*/
private static void edgeSplitMoveExceptionsAndResults(SsaMethod ssaMeth) {
ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
- // New blocks are added to the end of the block list during
- // this iteration
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
for (int i = blocks.size() - 1; i >= 0; i-- ) {
SsaBasicBlock block = blocks.get(i);
-
- // Any block that starts with a move-exception and has more than
- // one predecessor...
+
+ /*
+ * Any block that starts with a move-exception and has more than
+ * one predecessor...
+ */
if (!block.isExitBlock()
- && block.getPredecessors().cardinality() > 1
+ && block.getPredecessors().cardinality() > 1
&& block.getInsns().get(0).isMoveException()) {
- // block.getPredecessors() is changed in the loop below
+ // block.getPredecessors() is changed in the loop below.
BitSet preds = (BitSet)block.getPredecessors().clone();
for (int j = preds.nextSetBit(0); j >= 0;
- j = preds.nextSetBit(j + 1)) {
-
+ j = preds.nextSetBit(j + 1)) {
SsaBasicBlock predecessor = blocks.get(j);
+ SsaBasicBlock zNode
+ = predecessor.insertNewSuccessor(block);
- SsaBasicBlock zNode = predecessor.insertNewSuccessor(block);
-
- // Make sure to place the move-exception as the
- // first insn...
+ /*
+ * Make sure to place the move-exception as the
+ * first insn.
+ */
zNode.getInsns().add(0, block.getInsns().get(0).clone());
}
- // remove the move-exception from the original block...
+ // Remove the move-exception from the original block.
block.getInsns().remove(0);
}
}
}
/**
- * Inserts Z nodes for every node that needs a new
+ * Inserts Z nodes for every node that needs a new
* successor.
- * @param result non-null; method to process
+ *
+ * @param result {@code non-null;} method to process
*/
private static void edgeSplitSuccessors(SsaMethod result) {
ArrayList<SsaBasicBlock> blocks = result.getBlocks();
- // New blocks are added to the end of the block list during
- // this iteration
+ /*
+ * New blocks are added to the end of the block list during
+ * this iteration.
+ */
for (int i = blocks.size() - 1; i >= 0; i-- ) {
SsaBasicBlock block = blocks.get(i);
- // successors list is modified in loop below
+ // Successors list is modified in loop below.
BitSet successors = (BitSet)block.getSuccessors().clone();
- for(int j = successors.nextSetBit(0);
- j >= 0; j = successors.nextSetBit(j+1)) {
+ for (int j = successors.nextSetBit(0);
+ j >= 0; j = successors.nextSetBit(j+1)) {
SsaBasicBlock succ = blocks.get(j);
@@ -225,17 +241,17 @@
}
/**
- * Returns true if block and successor need a Z-node between them.
- * Presently, this is true if the final instruction has any sources
- * or results and the current successor block has more than one
- * predecessor.
+ * Returns {@code true} if block and successor need a Z-node
+ * between them. Presently, this is {@code true} if the final
+ * instruction has any sources or results and the current
+ * successor block has more than one predecessor.
+ *
* @param block predecessor node
* @param succ successor node
- * @return true if a Z node is needed
+ * @return {@code true} if a Z node is needed
*/
private static boolean needsNewSuccessor(SsaBasicBlock block,
SsaBasicBlock succ) {
-
ArrayList<SsaInsn> insns = block.getInsns();
SsaInsn lastInsn = insns.get(insns.size() - 1);
@@ -245,11 +261,14 @@
}
/**
- * See Appel algorithm 19.6
+ * See Appel algorithm 19.6:
+ *
* Place Phi functions in appropriate locations.
*
- * @param ssaMeth non-null; method to process. Modifications made in-place
- * @param localInfo non-null; Local variable info, used when placing phis
+ * @param ssaMeth {@code non-null;} method to process.
+ * Modifications are made in-place.
+ * @param localInfo {@code non-null;} local variable info, used
+ * when placing phis
*/
private static void placePhiFunctions (SsaMethod ssaMeth,
LocalVariableInfo localInfo) {
@@ -282,8 +301,7 @@
for (int bi = 0, s = ssaBlocks.size(); bi < s; bi++) {
SsaBasicBlock b = ssaBlocks.get(bi);
- for (SsaInsn insn: b.getInsns()) {
-
+ for (SsaInsn insn : b.getInsns()) {
RegisterSpec rs = insn.getResult();
if (rs != null) {
@@ -297,11 +315,8 @@
for (int i = 0; i < regCount; i++) {
StringBuilder sb = new StringBuilder();
-
sb.append('v').append(i).append(": ");
-
sb.append(defsites[i].toString());
-
System.out.println(sb);
}
}
@@ -315,15 +330,14 @@
for (int reg = 0, s = ssaMeth.getRegCount() ; reg < s ; reg++ ) {
int workBlockIndex;
- /* Worklist set starts out with each node where reg is assigned */
+ /* Worklist set starts out with each node where reg is assigned. */
- worklist = (BitSet)(defsites[reg].clone());
+ worklist = (BitSet) (defsites[reg].clone());
while (0 <= (workBlockIndex = worklist.nextSetBit(0))) {
worklist.clear(workBlockIndex);
IntIterator dfIterator
- = domInfos[workBlockIndex]
- .dominanceFrontiers.iterator();
+ = domInfos[workBlockIndex].dominanceFrontiers.iterator();
while (dfIterator.hasNext()) {
int dfBlockIndex = dfIterator.next();
@@ -353,11 +367,8 @@
for (int i = 0; i < regCount; i++) {
StringBuilder sb = new StringBuilder();
-
sb.append('v').append(i).append(": ");
-
sb.append(phisites[i].toString());
-
System.out.println(sb);
}
}
diff --git a/dx/src/com/android/dx/ssa/SsaInsn.java b/dx/src/com/android/dx/ssa/SsaInsn.java
index d9e33a0..815f82d 100644
--- a/dx/src/com/android/dx/ssa/SsaInsn.java
+++ b/dx/src/com/android/dx/ssa/SsaInsn.java
@@ -23,24 +23,34 @@
* An instruction in SSA form
*/
public abstract class SsaInsn implements ToHuman, Cloneable {
+ /** {@code non-null;} the block that contains this instance */
+ private final SsaBasicBlock block;
- protected RegisterSpec result;
- protected final SsaBasicBlock block;
+ /** {@code null-ok;} result register */
+ private RegisterSpec result;
/**
- * Constructs an instance
- * @param block block containing this insn. Can never change.
+ * 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.
*/
- protected SsaInsn(final SsaBasicBlock block) {
+ protected SsaInsn(RegisterSpec result, SsaBasicBlock block) {
+ if (block == null) {
+ throw new NullPointerException("block == null");
+ }
+
this.block = block;
+ this.result = result;
}
/**
- * Makes a new SSA insn form a ROP insn
+ * Makes a new SSA insn form a rop insn.
*
- * @param insn non-null; rop insn
- * @param block non-null; owning block
- * @return non-null; an appropriately constructed instance
+ * @param insn {@code non-null;} rop insn
+ * @param block {@code non-null;} owning block
+ * @return {@code non-null;} an appropriately constructed instance
*/
public static SsaInsn makeFromRop(Insn insn, SsaBasicBlock block) {
return new NormalSsaInsn(insn, block);
@@ -58,6 +68,7 @@
/**
* Like {@link com.android.dx.rop.code.Insn getResult()}.
+ *
* @return result register
*/
public RegisterSpec getResult() {
@@ -65,8 +76,22 @@
}
/**
+ * Set the result register.
+ *
+ * @param result {@code non-null;} the new result register
+ */
+ protected void setResult(RegisterSpec result) {
+ if (result == null) {
+ throw new NullPointerException("result == null");
+ }
+
+ this.result = result;
+ }
+
+ /**
* Like {@link com.android.dx.rop.code.Insn getSources()}.
- * @return non-null; sources list
+ *
+ * @return {@code non-null;} sources list
*/
abstract public RegisterSpecList getSources();
@@ -80,7 +105,8 @@
}
/**
- * is the specified reg the result reg?
+ * 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
@@ -91,9 +117,10 @@
/**
- * Changes the result register if this insn has a result.
- * Used during renaming.
- * @param reg new result register.
+ * 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) {
if (result != null) {
@@ -102,10 +129,10 @@
}
/**
- * Sets the local association for the result of this insn.
- * This is sometimes updated during the SsaRenamer process.
+ * Sets the local association for the result of this insn. This is
+ * sometimes updated during the SsaRenamer process.
*
- * @param local null-ok; New debug/local variable info.
+ * @param local {@code null-ok;} new debug/local variable info
*/
public final void setResultLocal(LocalItem local) {
LocalItem oldItem = result.getLocalItem();
@@ -120,10 +147,11 @@
/**
* Map registers after register allocation.
*
- * @param mapper
+ * @param mapper {@code non-null;} mapping from old to new registers
*/
public final void mapRegisters(RegisterMapper mapper) {
RegisterSpec oldResult = result;
+
result = mapper.map(result);
block.getParent().updateOneDefinition(this, oldResult);
mapSourceRegisters(mapper);
@@ -136,13 +164,12 @@
*/
abstract public void mapSourceRegisters(RegisterMapper mapper);
-
/**
- * Returns the Rop opcode for this insn, or null if this is a phi insn
+ * Returns the Rop opcode for this insn, or null if this is a phi insn.
*
- * TODO move this up into NormalSsaInsn
+ * TODO: Move this up into NormalSsaInsn.
*
- * @return null-ok; Rop opcode if there is one.
+ * @return {@code null-ok;} Rop opcode if there is one.
*/
abstract public Rop getOpcode();
@@ -150,20 +177,21 @@
* Returns the original Rop insn for this insn, or null if this is
* a phi insn.
*
- * TODO move this up into NormalSsaInsn
+ * TODO: Move this up into NormalSsaInsn.
*
- * @return null-ok; Rop insn if there is one.
+ * @return {@code null-ok;} Rop insn if there is one.
*/
abstract public Insn getOriginalRopInsn();
/**
* Gets the spec of a local variable assignment that occurs at this
* instruction, or null if no local variable assignment occurs. This
- * may be the result register, or for <code>mark-local</code> insns
+ * may be the result register, or for {@code mark-local} insns
* it may be the source.
*
- * @return null-ok; a local-associated register spec or null
* @see com.android.dx.rop.code.Insn#getLocalAssignment()
+ *
+ * @return {@code null-ok;} a local-associated register spec or null
*/
public RegisterSpec getLocalAssignment() {
if (result != null && result.getLocalItem() != null) {
@@ -176,7 +204,8 @@
/**
* Indicates whether the specified register is amongst the registers
* used as sources for this instruction.
- * @param reg The register in question
+ *
+ * @param reg the register in question
* @return true if the reg is a source
*/
public boolean isRegASource(int reg) {
@@ -186,9 +215,9 @@
/**
* Transform back to ROP form.
*
- * TODO move this up into NormalSsaInsn
+ * TODO: Move this up into NormalSsaInsn.
*
- * @return non-null; a ROP representation of this instruction, with
+ * @return {@code non-null;} a ROP representation of this instruction, with
* updated registers.
*/
public abstract Insn toRopInsn();
@@ -208,8 +237,8 @@
public abstract boolean hasSideEffect();
/**
- * @return true if this is a move (but not a move-operand or move-exception)
- * instruction
+ * @return true if this is a move (but not a move-operand or
+ * move-exception) instruction
*/
public boolean isNormalMoveInsn() {
return false;
@@ -229,8 +258,9 @@
abstract public boolean canThrow();
/**
- * accepts a visitor
- * @param v visitor
+ * Accepts a visitor.
+ *
+ * @param v {@code non-null} the visitor
*/
public abstract void accept(Visitor v);
@@ -238,22 +268,21 @@
* Visitor interface for this class.
*/
public static interface Visitor {
-
/**
* Any non-phi move instruction
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitMoveInsn(NormalSsaInsn insn);
/**
* Any phi insn
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitPhiInsn(PhiInsn insn);
/**
* Any insn that isn't a move or a phi (which is also a move).
- * @param insn non-null; the instruction to visit
+ * @param insn {@code non-null;} the instruction to visit
*/
public void visitNonMoveInsn(NormalSsaInsn insn);
}
diff --git a/dx/src/com/android/dx/ssa/SsaMethod.java b/dx/src/com/android/dx/ssa/SsaMethod.java
index 49f8ea5..073e515 100644
--- a/dx/src/com/android/dx/ssa/SsaMethod.java
+++ b/dx/src/com/android/dx/ssa/SsaMethod.java
@@ -36,10 +36,9 @@
import java.util.Set;
/**
- * A method in SSA form
+ * A method in SSA form.
*/
public final class SsaMethod {
-
/** basic blocks, indexed by block index */
private ArrayList<SsaBasicBlock> blocks;
@@ -48,12 +47,17 @@
/**
* Index of exit block, which exists only in SSA form,
- * or or -1 if there is none
+ * or or {@code -1} if there is none
*/
private int exitBlockIndex;
+ /** total number of registers required */
private int registerCount;
+
+ /** first register number to use for any temporary "spares" */
private int spareRegisterBase;
+
+ /** current count of spare registers used */
private int borrowedSpareRegisters;
/** really one greater than the max label */
@@ -62,7 +66,7 @@
/** the total width, in register-units, of the method's parameters */
private final int paramWidth;
- /** true if this method has no 'this' pointer argument */
+ /** true if this method has no {@code this} pointer argument */
private final boolean isStatic;
/**
@@ -73,6 +77,7 @@
/** indexed by register: the list of all insns that use a register */
private ArrayList<SsaInsn>[] useList;
+
/** A version of useList with each List unmodifiable */
private List<SsaInsn>[] unmodifiableUseList;
@@ -81,47 +86,58 @@
* are about to be mapped into a non-SSA namespace. When true,
* use and def lists are unavailable.
*
- * TODO remove this mode, plase the functionality elsewhere
+ * TODO: Remove this mode, and place the functionality elsewhere
*/
- private boolean backMode = false;
+ private boolean backMode;
/**
- * @param rmeth RopMethod to convert from
+ * @param ropMethod rop-form method to convert from
* @param paramWidth the total width, in register-units, of the
* method's parameters
- * @param isStatic true if this method has no 'this' pointer argument
- * @return SsaMethod representation
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
*/
- static SsaMethod newFromRopMethod(RopMethod rmeth, int paramWidth,
- boolean isStatic) {
- SsaMethod result;
+ public static SsaMethod newFromRopMethod(RopMethod ropMethod,
+ int paramWidth, boolean isStatic) {
+ SsaMethod result = new SsaMethod(ropMethod, paramWidth, isStatic);
- result = new SsaMethod(paramWidth, isStatic);
-
- result.maxLabel = rmeth.getBlocks().getMaxLabel();
- result.registerCount = rmeth.getBlocks().getRegCount();
- result.spareRegisterBase = result.registerCount;
-
- result.convertRopToSsaBlocks(rmeth);
+ result.convertRopToSsaBlocks(ropMethod);
return result;
}
/**
+ * Constructs an instance.
+ *
+ * @param ropMethod {@code non-null;} the original rop-form method that
+ * this instance is based on
+ * @param paramWidth the total width, in register-units, of the
+ * method's parameters
+ * @param isStatic {@code true} if this method has no {@code this}
+ * pointer argument
+ */
+ private SsaMethod(RopMethod ropMethod, int paramWidth, boolean isStatic) {
+ this.paramWidth = paramWidth;
+ this.isStatic = isStatic;
+ this.backMode = false;
+ this.maxLabel = ropMethod.getBlocks().getMaxLabel();
+ this.registerCount = ropMethod.getBlocks().getRegCount();
+ this.spareRegisterBase = registerCount;
+ }
+
+ /**
* Builds a BitSet of block indices from a basic block list and a list
- * of labels taken from Rop form
+ * of labels taken from Rop form.
+ *
* @param blocks Rop blocks
* @param labelList list of rop block labels
* @return BitSet of block indices
*/
static BitSet bitSetFromLabelList(BasicBlockList blocks,
IntList labelList) {
+ BitSet result = new BitSet(blocks.size());
- BitSet result;
-
- result = new BitSet(blocks.size());
-
- for (int i = 0, sz = labelList.size() ; i < sz ; i++) {
+ for (int i = 0, sz = labelList.size(); i < sz; i++) {
result.set(blocks.indexOfLabel(labelList.get(i)));
}
@@ -130,7 +146,8 @@
/**
* Builds an IntList of block indices from a basic block list and a list
- * of labels taken from Rop form
+ * of labels taken from Rop form.
+ *
* @param ropBlocks Rop blocks
* @param labelList list of rop block labels
* @return IntList of block indices
@@ -138,35 +155,27 @@
public static IntList indexListFromLabelList(BasicBlockList ropBlocks,
IntList labelList) {
- IntList result;
+ IntList result = new IntList(labelList.size());
- result = new IntList(labelList.size());
-
- for (int i = 0, sz = labelList.size() ; i < sz ; i++) {
+ for (int i = 0, sz = labelList.size(); i < sz; i++) {
result.add(ropBlocks.indexOfLabel(labelList.get(i)));
}
return result;
}
- private void convertRopToSsaBlocks(
- RopMethod rmeth) {
+ private void convertRopToSsaBlocks(RopMethod rmeth) {
+ BasicBlockList ropBlocks = rmeth.getBlocks();
+ int sz = ropBlocks.size();
- BasicBlockList ropBlocks;
+ blocks = new ArrayList<SsaBasicBlock>(sz + 2);
- ropBlocks = rmeth.getBlocks();
-
- blocks = new ArrayList<SsaBasicBlock>(ropBlocks.size() + 2);
-
- for (int i = 0, sz = ropBlocks.size() ; i < sz ; i++) {
- SsaBasicBlock sbb;
-
- sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
-
+ for (int i = 0; i < sz; i++) {
+ SsaBasicBlock sbb = SsaBasicBlock.newFromRop(rmeth, i, this);
blocks.add(sbb);
}
- // Add an no-op entry block
+ // Add an no-op entry block.
int origEntryBlockIndex = rmeth.getBlocks()
.indexOfLabel(rmeth.getFirstLabel());
@@ -174,18 +183,16 @@
= blocks.get(origEntryBlockIndex).insertNewPredecessor();
entryBlockIndex = entryBlock.getIndex();
- exitBlockIndex = -1; // this gets made later
-
+ exitBlockIndex = -1; // This gets made later.
}
-
/**
* Creates an exit block and attaches it to the CFG if this method
* exits. Methods that never exit will not have an exit block. This
* is called after edge-splitting and phi insertion, since the edges
* going into the exit block should not be considered in those steps.
*/
- void makeExitBlock() {
+ /*package*/ void makeExitBlock() {
if (exitBlockIndex >= 0) {
throw new RuntimeException("must be called at most once");
}
@@ -196,7 +203,7 @@
blocks.add(exitBlock);
- for (SsaBasicBlock block: blocks) {
+ for (SsaBasicBlock block : blocks) {
block.exitBlockFixup(exitBlock);
}
@@ -209,22 +216,10 @@
}
/**
- * Constructor
- *
- * @param paramWidth the total width, in register-units, of the
- * method's parameters
- * @param isStatic true if this method has no 'this' pointer argument
- */
- private SsaMethod(int paramWidth, boolean isStatic) {
- this.paramWidth = paramWidth;
- this.isStatic = isStatic;
- }
-
- /**
- * Gets a new GOTO insn.
+ * Gets a new {@code GOTO} insn.
*
* @param block block to which this GOTO will be added
- * (not it's destination!)
+ * (not it's destination!)
* @return an appropriately-constructed instance.
*/
private static SsaInsn getGoto(SsaBasicBlock block) {
@@ -232,11 +227,11 @@
new PlainInsn(Rops.GOTO, SourcePosition.NO_INFO,
null, RegisterSpecList.EMPTY), block);
}
-
+
/**
- * Makes a new basic block for this method,
- * which is empty besides a single <code>GOTO</code>. Successors and
- * predecessors are not yet set.
+ * Makes a new basic block for this method, which is empty besides
+ * a single {@code GOTO}. Successors and predecessors are not yet
+ * set.
*
* @return new block
*/
@@ -265,22 +260,23 @@
}
/**
- * @return block index of exit block or -1 if there is none
+ * @return block index of exit block or {@code -1} if there is none
*/
public int getExitBlockIndex() {
return exitBlockIndex;
}
/**
- * @return null-ok; block of exit block or null if there is none
+ * @return {@code null-ok;} block of exit block or {@code null} if
+ * there is none
*/
public SsaBasicBlock getExitBlock() {
return exitBlockIndex < 0 ? null : blocks.get(exitBlockIndex);
}
/**
- * @param bi block index or -1 for none
- * @return rop label or -1 if bi was -1
+ * @param bi block index or {@code -1} for none
+ * @return rop label or {code -1} if {@code bi} was {@code -1}
*/
public int blockIndexToRopLabel(int bi) {
if (bi < 0) {
@@ -297,7 +293,7 @@
}
/**
- * @return the total width, in register units, of the method's
+ * @return the total width, in register units, of the method's
* parameters
*/
public int getParamWidth() {
@@ -305,27 +301,25 @@
}
/**
- * Returns true if this is a static method.
+ * Returns {@code true} if this is a static method.
*
- * @return true if this is a static method
+ * @return {@code true} if this is a static method
*/
public boolean isStatic() {
return isStatic;
}
/**
- * Borrow a register to use as a temp. Used in the phi removal process.
+ * Borrows a register to use as a temp. Used in the phi removal process.
* Call returnSpareRegisters() when done.
+ *
* @param category width (1 or 2) of the register
* @return register number to use
*/
public int borrowSpareRegister(int category) {
- int result;
-
- result = spareRegisterBase + borrowedSpareRegisters;
+ int result = spareRegisterBase + borrowedSpareRegisters;
borrowedSpareRegisters += category;
-
registerCount = Math.max(registerCount, result + category);
return result;
@@ -339,7 +333,7 @@
}
/**
- * @return non-null; basic block list, do not modify.
+ * @return {@code non-null;} basic block list. Do not modify.
*/
public ArrayList<SsaBasicBlock> getBlocks() {
return blocks;
@@ -349,12 +343,12 @@
* Returns the count of reachable blocks in this method: blocks that have
* predecessors (or are the start block)
*
- * @return >= 0; number of reachable basic blocks
+ * @return {@code >= 0;} number of reachable basic blocks
*/
public int getCountReachableBlocks() {
int ret = 0;
- for (SsaBasicBlock b: blocks) {
+ for (SsaBasicBlock b : blocks) {
// Blocks that have been disconnected don't count.
if (b.isReachable()) {
ret++;
@@ -366,16 +360,16 @@
/**
* Remaps unversioned registers.
+ *
* @param mapper maps old registers to new.
*/
public void mapRegisters(RegisterMapper mapper) {
-
- for (SsaBasicBlock block: getBlocks()) {
- for (SsaInsn insn: block.getInsns()) {
+ for (SsaBasicBlock block : getBlocks()) {
+ for (SsaInsn insn : block.getInsns()) {
insn.mapRegisters(mapper);
}
- }
-
+ }
+
registerCount = mapper.getNewRegisterCount();
spareRegisterBase = registerCount;
}
@@ -425,7 +419,7 @@
useList = new ArrayList[registerCount];
- for (int i = 0 ; i < registerCount; i++) {
+ for (int i = 0; i < registerCount; i++) {
useList[i] = new ArrayList();
}
@@ -444,7 +438,7 @@
}
/**
* Adds specified insn to the uses list for all of its sources.
- * @param insn non-null; insn to process
+ * @param insn {@code non-null;} insn to process
*/
private void addToUses(SsaInsn insn) {
RegisterSpecList rl = insn.getSources();
@@ -458,7 +452,7 @@
unmodifiableUseList = new List[registerCount];
- for (int i = 0 ; i < registerCount; i++) {
+ for (int i = 0; i < registerCount; i++) {
unmodifiableUseList[i] = Collections.unmodifiableList(useList[i]);
}
}
@@ -466,15 +460,15 @@
/**
* Updates the use list for a single change in source register.
*
- * @param insn non-null; insn being changed
- * @param oldSource null-ok; The source that was used, if applicable
- * @param newSource non-null; the new source being used
+ * @param insn {@code non-null;} insn being changed
+ * @param oldSource {@code null-ok;} The source that was used, if
+ * applicable
+ * @param newSource {@code non-null;} the new source being used
*/
- void onSourceChanged(SsaInsn insn,
+ /*package*/ void onSourceChanged(SsaInsn insn,
RegisterSpec oldSource, RegisterSpec newSource) {
-
if (useList == null) return;
-
+
if (oldSource != null) {
int reg = oldSource.getReg();
useList[reg].remove(insn);
@@ -491,11 +485,13 @@
/**
* Updates the use list for a source list change.
*
- * @param insn insn non-null; insn being changed. insn.getSources()
- * must return the new source list.
- * @param oldSources null-ok; list of sources that were previously used.
+ * @param insn {@code insn non-null;} insn being changed.
+ * {@code insn.getSources()} must return the new source list.
+ * @param oldSources {@code null-ok;} list of sources that were
+ * previously used
*/
- void onSourcesChanged(SsaInsn insn, RegisterSpecList oldSources) {
+ /*package*/ void onSourcesChanged(SsaInsn insn,
+ RegisterSpecList oldSources) {
if (useList == null) return;
if (oldSources != null) {
@@ -505,27 +501,28 @@
RegisterSpecList sources = insn.getSources();
int szNew = sources.size();
- for(int i = 0; i < szNew; i++) {
+ for (int i = 0; i < szNew; i++) {
int reg = sources.get(i).getReg();
useList[reg].add(insn);
- }
+ }
}
/**
- * Removes a given <code>insn</code> from the use lists for the given
- * <code>oldSources</code> (rather than the sources currently
+ * Removes a given {@code insn} from the use lists for the given
+ * {@code oldSources} (rather than the sources currently
* returned by insn.getSources()).
*
- * @param insn non-null; insn in question
- * @param oldSources null-ok; registers whose use lists <code>insn</code>
- * should be removed form.
+ * @param insn {@code non-null;} insn in question
+ * @param oldSources {@code null-ok;} registers whose use lists
+ * {@code insn} should be removed form
*/
private void removeFromUseList(SsaInsn insn, RegisterSpecList oldSources) {
if (oldSources == null) {
return;
}
+
int szNew = oldSources.size();
- for(int i = 0; i < szNew; i++) {
+ for (int i = 0; i < szNew; i++) {
if (!useList[oldSources.get(i).getReg()].remove(insn)) {
throw new RuntimeException("use not found");
}
@@ -536,35 +533,35 @@
* Adds an insn to both the use and def lists. For use when adding
* a new insn to the method.
*
- * @param insn non-null; insn to add
+ * @param insn {@code non-null;} insn to add
*/
- void onInsnAdded(SsaInsn insn) {
+ /*package*/ void onInsnAdded(SsaInsn insn) {
onSourcesChanged(insn, null);
updateOneDefinition(insn, null);
}
/**
- * Removes an instruction from use and def lists. For use during
- * instruction removal.
- *
- * @param insn non-null; insn to remove.
- */
- void onInsnRemoved(SsaInsn insn) {
- if (useList != null) {
- removeFromUseList(insn, insn.getSources());
- }
+ * Removes an instruction from use and def lists. For use during
+ * instruction removal.
+ *
+ * @param insn {@code non-null;} insn to remove
+ */
+ /*package*/ void onInsnRemoved(SsaInsn insn) {
+ if (useList != null) {
+ removeFromUseList(insn, insn.getSources());
+ }
- RegisterSpec resultReg = insn.getResult();
- if (definitionList != null && resultReg != null) {
- definitionList[resultReg.getReg()] = null;
- }
- }
+ RegisterSpec resultReg = insn.getResult();
+ if (definitionList != null && resultReg != null) {
+ definitionList[resultReg.getReg()] = null;
+ }
+ }
/**
* Indicates that the instruction list has changed or the SSA register
* count has increased, so that internal datastructures that rely on
* it should be rebuild. In general, the various other on* methods
- * should be called in preference when changes occur if they are
+ * should be called in preference when changes occur if they are
* applicable.
*/
public void onInsnsChanged() {
@@ -579,19 +576,22 @@
/**
* Updates a single definition.
*
- * @param insn non-null; insn who's result should be recorded as
+ * @param insn {@code non-null;} insn who's result should be recorded as
* a definition
- * @param oldResult null-ok; a previous result that should be no longer
- * considered a definition by this insn
+ * @param oldResult {@code null-ok;} a previous result that should
+ * be no longer considered a definition by this insn
*/
- void updateOneDefinition(SsaInsn insn, RegisterSpec oldResult) {
+ /*package*/ void updateOneDefinition(SsaInsn insn,
+ RegisterSpec oldResult) {
if (definitionList == null) return;
+
if (oldResult != null) {
int reg = oldResult.getReg();
definitionList[reg] = null;
}
RegisterSpec resultReg = insn.getResult();
+
if (resultReg != null) {
int reg = resultReg.getReg();
@@ -604,7 +604,8 @@
}
/**
- * Returns the list of all source uses (not results) for a register
+ * Returns the list of all source uses (not results) for a register.
+ *
* @param reg register in question
* @return unmodifiable instruction list
*/
@@ -619,6 +620,7 @@
/**
* Returns a modifiable copy of the register use list.
+ *
* @return modifiable copy of the use-list, indexed by register
*/
public ArrayList<SsaInsn>[] getUseListCopy() {
@@ -641,7 +643,7 @@
* local variable. Each SSA reg may be associated with at most one
* local var.
*
- * @param spec non-null; ssa reg
+ * @param spec {@code non-null;} ssa reg
* @return true if reg is ever associated with a local
*/
public boolean isRegALocal(RegisterSpec spec) {
@@ -656,7 +658,7 @@
if (defn.getLocalAssignment() != null) return true;
// If not, is there a mark-local insn?
- for (SsaInsn use: getUseListForRegister(spec.getReg())) {
+ for (SsaInsn use : getUseListForRegister(spec.getReg())) {
Insn insn = use.getOriginalRopInsn();
if (insn != null
@@ -664,12 +666,13 @@
return true;
}
}
-
+
return false;
}
/**
* Sets the new register count after renaming.
+ *
* @param newRegCount new register count
*/
/*package*/ void setNewRegCount(int newRegCount) {
@@ -681,48 +684,52 @@
/**
* Makes a new SSA register. For use after renaming has completed.
*
- * @return >=0 new SSA register.
+ * @return {@code >=0;} new SSA register.
*/
public int makeNewSsaReg() {
int reg = registerCount++;
spareRegisterBase = registerCount;
onInsnsChanged();
- return reg;
+ return reg;
}
/**
- * Visit all insns in this method
- * @param visitor non-null; callback interface
+ * Visits all insns in this method.
+ *
+ * @param visitor {@code non-null;} callback interface
*/
public void forEachInsn(SsaInsn.Visitor visitor) {
- for (SsaBasicBlock block: blocks) {
+ for (SsaBasicBlock block : blocks) {
block.forEachInsn(visitor);
}
}
/**
* Visits each phi insn in this method
- * @param v non-null; callback
+ * @param v {@code non-null;} callback.
+ *
*/
public void forEachPhiInsn(PhiInsn.Visitor v) {
- for (SsaBasicBlock block: blocks) {
+ for (SsaBasicBlock block : blocks) {
block.forEachPhiInsn(v);
}
}
/**
- * Walk the basic block tree in depth-first order, calling the visitor
+ * Walks the basic block tree in depth-first order, calling the visitor
* method once for every block. This depth-first walk may be run forward
* from the method entry point or backwards from the method exit points.
+ *
* @param reverse true if this should walk backwards from the exit points
- * @param v non-null; callback interface. <code>parent</code>is set
+ * @param v {@code non-null;} callback interface. {@code parent} is set
* unless this is the root node
*/
public void forEachBlockDepthFirst(boolean reverse,
SsaBasicBlock.Visitor v) {
BitSet visited = new BitSet(blocks.size());
- // We push the parent first, then the child on the stack
+
+ // We push the parent first, then the child on the stack.
Stack<SsaBasicBlock> stack = new Stack<SsaBasicBlock>();
SsaBasicBlock rootBlock = reverse ? getExitBlock() : getEntryBlock();
@@ -732,7 +739,7 @@
return;
}
- stack.add(null); // start with null parent
+ stack.add(null); // Start with null parent.
stack.add(rootBlock);
while (stack.size() > 0) {
@@ -741,7 +748,7 @@
if (!visited.get(cur.getIndex())) {
BitSet children
- = reverse ? cur.getPredecessors() : cur.getSuccessors();
+ = reverse ? cur.getPredecessors() : cur.getSuccessors();
for (int i = children.nextSetBit(0); i >= 0
; i = children.nextSetBit(i + 1)) {
stack.add(cur);
@@ -755,10 +762,10 @@
/**
* Visits blocks in dom-tree order, starting at the current node.
- * The <code>parent</code> parameter of the Visitor.visitBlock callback
+ * The {@code parent} parameter of the Visitor.visitBlock callback
* is currently always set to null.
*
- * @param v non-null; callback interface
+ * @param v {@code non-null;} callback interface
*/
public void forEachBlockDepthFirstDom(SsaBasicBlock.Visitor v) {
BitSet visited = new BitSet(getBlocks().size());
@@ -783,12 +790,12 @@
}
/**
- * Deletes all insns in the set from this method
+ * Deletes all insns in the set from this method.
*
- * @param deletedInsns non-null; insns to delete
+ * @param deletedInsns {@code non-null;} insns to delete
*/
public void deleteInsns(Set<SsaInsn> deletedInsns) {
- for (SsaBasicBlock block: getBlocks()) {
+ for (SsaBasicBlock block : getBlocks()) {
ArrayList<SsaInsn> insns = block.getInsns();
for (int i = insns.size() - 1; i >= 0; i--) {
@@ -819,7 +826,7 @@
}
/**
- * Set "back-convert mode". Set during back-conversion when registers
+ * Sets "back-convert mode". Set during back-conversion when registers
* are about to be mapped into a non-SSA namespace. When true,
* use and def lists are unavailable.
*/
diff --git a/dx/src/com/android/dx/ssa/SsaRenamer.java b/dx/src/com/android/dx/ssa/SsaRenamer.java
index 64bad2c..8452c03 100644
--- a/dx/src/com/android/dx/ssa/SsaRenamer.java
+++ b/dx/src/com/android/dx/ssa/SsaRenamer.java
@@ -54,11 +54,11 @@
* current block has been processed, this mapping table is then copied
* and used as the initial state for child blocks.<p>
*/
-class SsaRenamer implements Runnable {
-
+public class SsaRenamer implements Runnable {
+ /** debug flag */
private static final boolean DEBUG = false;
- /** Method we're processing */
+ /** method we're processing */
private final SsaMethod ssaMeth;
/** next available SSA register */
@@ -68,10 +68,10 @@
private final int ropRegCount;
/**
- * Indexed by block index; register version state for each block start.
+ * indexed by block index; register version state for each block start.
* This list is updated by each dom parent for its children. The only
* sub-arrays that exist at any one time are the start states for blocks
- * yet to be processed by a <code>BlockRenamer</code> instance.
+ * yet to be processed by a {@code BlockRenamer} instance.
*/
private final RegisterSpec[][] startsForBlocks;
@@ -79,24 +79,25 @@
private final ArrayList<LocalItem> ssaRegToLocalItems;
/**
- * Maps SSA registers back to the original rop number.
- * Used for debug only.
+ * maps SSA registers back to the original rop number. Used for
+ * debug only.
*/
private IntList ssaRegToRopReg;
/**
* Constructs an instance of the renamer
*
- * @param ssaMeth non-null; un-renamed SSA method that will
+ * @param ssaMeth {@code non-null;} un-renamed SSA method that will
* be renamed.
*/
- SsaRenamer (final SsaMethod ssaMeth) {
+ public SsaRenamer(SsaMethod ssaMeth) {
ropRegCount = ssaMeth.getRegCount();
this.ssaMeth = ssaMeth;
+
/*
* Reserve the first N registers in the SSA register space for
- * "version 0" registers
+ * "version 0" registers.
*/
nextSsaReg = ropRegCount;
startsForBlocks = new RegisterSpec[ssaMeth.getBlocks().size()][];
@@ -138,10 +139,10 @@
* in-place.
*/
public void run() {
-
// Rename each block in dom-tree DFS order.
ssaMeth.forEachBlockDepthFirstDom(new SsaBasicBlock.Visitor() {
- public void visitBlock (SsaBasicBlock block, SsaBasicBlock unused) {
+ public void visitBlock (SsaBasicBlock block,
+ SsaBasicBlock unused) {
new BlockRenamer(block).process();
}
});
@@ -151,15 +152,17 @@
if (DEBUG) {
System.out.println("SSA\tRop");
- // We're going to compute the version of the rop register
- // by keeping a running total of how many times the rop register
- // has been mapped.
+ /*
+ * We're going to compute the version of the rop register
+ * by keeping a running total of how many times the rop
+ * register has been mapped.
+ */
int[] versions = new int[ropRegCount];
int sz = ssaRegToRopReg.size();
- for(int i = 0; i < sz; i++) {
- int ropReg = ssaRegToRopReg.get(i);
- System.out.println(i +"\t" + ropReg + "["
+ for (int i = 0; i < sz; i++) {
+ int ropReg = ssaRegToRopReg.get(i);
+ System.out.println(i + "\t" + ropReg + "["
+ versions[ropReg] + "]");
versions[ropReg]++;
}
@@ -167,9 +170,10 @@
}
/**
- * Duplicates a RegisterSpec array
- * @param orig non-null; array to duplicate
- * @return non-null; new instance
+ * Duplicates a RegisterSpec array.
+ *
+ * @param orig {@code non-null;} array to duplicate
+ * @return {@code non-null;} new instance
*/
private static RegisterSpec[] dupArray(RegisterSpec[] orig) {
RegisterSpec[] copy = new RegisterSpec[orig.length];
@@ -183,7 +187,7 @@
* Gets a local variable item for a specified register.
*
* @param ssaReg register in SSA name space
- * @return null-ok; Local variable name or null if none
+ * @return {@code null-ok;} Local variable name or null if none
*/
private LocalItem getLocalForNewReg(int ssaReg) {
if (ssaReg < ssaRegToLocalItems.size()) {
@@ -223,8 +227,8 @@
}
/**
- * Returns true if a and b are equal or are both null
-
+ * Returns true if a and b are equal or are both null.
+ *
* @param a null-ok
* @param b null-ok
* @return Returns true if a and b are equal or are both null
@@ -238,26 +242,26 @@
* as appropriate.
*/
private class BlockRenamer implements SsaInsn.Visitor{
- /** non-null; block we're processing. */
+ /** {@code non-null;} block we're processing. */
private final SsaBasicBlock block;
/**
- * non-null; indexed by old register name. The current top of the
- * version stack as seen by this block. It's initialized from
- * the ending state of its dom parent, updated as the block's
- * instructions are processed, and then copied to each one of its
- * dom children.
+ * {@code non-null;} indexed by old register name. The current
+ * top of the version stack as seen by this block. It's
+ * initialized from the ending state of its dom parent,
+ * updated as the block's instructions are processed, and then
+ * copied to each one of its dom children.
*/
private final RegisterSpec[] currentMapping;
/**
- * Contains the set of moves we need to keep
- * to preserve local var info. All other moves will be deleted.
+ * contains the set of moves we need to keep to preserve local
+ * var info. All other moves will be deleted.
*/
private final HashSet<SsaInsn> movesToKeep;
/**
- * Maps the set of insns to replace after renaming is finished
+ * maps the set of insns to replace after renaming is finished
* on the block.
*/
private final HashMap<SsaInsn, SsaInsn> insnsToReplace;
@@ -265,10 +269,10 @@
private final RenamingMapper mapper;
/**
- * Constructs a block renamer instance. Call <code>process</code>
+ * Constructs a block renamer instance. Call {@code process}
* to process.
*
- * @param block non-null; block to process
+ * @param block {@code non-null;} block to process
*/
BlockRenamer(final SsaBasicBlock block) {
this.block = block;
@@ -287,8 +291,8 @@
* as the current block's instructions are processed.
*/
private class RenamingMapper extends RegisterMapper {
-
- RenamingMapper() {
+ public RenamingMapper() {
+ // This space intentionally left blank.
}
/** {@inheritDoc} */
@@ -304,8 +308,8 @@
int reg = registerSpec.getReg();
- // for debugging: assert that the mapped types are compatible
- if(DEBUG) {
+ // For debugging: assert that the mapped types are compatible.
+ if (DEBUG) {
RegisterSpec newVersion = currentMapping[reg];
if (newVersion.getBasicType() != Type.BT_VOID
&& registerSpec.getBasicFrameType()
@@ -338,7 +342,7 @@
updateSuccessorPhis();
- // Delete all move insns in this block
+ // Delete all move insns in this block.
ArrayList<SsaInsn> insns = block.getInsns();
int szInsns = insns.size();
@@ -349,29 +353,27 @@
replaceInsn = insnsToReplace.get(insn);
if (replaceInsn != null) {
- insns.set(i, replaceInsn);
+ insns.set(i, replaceInsn);
} else if (insn.isNormalMoveInsn()
&& !movesToKeep.contains(insn)) {
insns.remove(i);
}
}
- // Store the start states for our dom children
+ // Store the start states for our dom children.
boolean first = true;
- for (SsaBasicBlock child: block.getDomChildren()) {
+ for (SsaBasicBlock child : block.getDomChildren()) {
if (child != block) {
- RegisterSpec[] childStart;
-
- // don't bother duplicating the array for the first child
- childStart = first ? currentMapping
- : dupArray(currentMapping);
+ // Don't bother duplicating the array for the first child.
+ RegisterSpec[] childStart = first ? currentMapping
+ : dupArray(currentMapping);
startsForBlocks[child.getIndex()] = childStart;
first = false;
}
}
- // currentMapping is owned by a child now
+ // currentMapping is owned by a child now.
}
/**
@@ -388,13 +390,13 @@
* local.
* <li> ensures that only one SSA register
* at a time is considered to be associated with a local variable. When
- * <code>currentMapping</code> is updated and the newly added element
+ * {@code currentMapping} is updated and the newly added element
* is named, strip that name from any other SSA registers.
* </ol>
*
- * @param ropReg >= 0 Rop register number
- * @param ssaReg non-null; An SSA register that has just
- * been added to <code>currentMapping</code>
+ * @param ropReg {@code >= 0;} rop register number
+ * @param ssaReg {@code non-null;} an SSA register that has just
+ * been added to {@code currentMapping}
*/
private void addMapping(int ropReg, RegisterSpec ssaReg) {
int ssaRegNum = ssaReg.getReg();
@@ -413,15 +415,15 @@
}
}
- // All further steps are for registers with local information
+ // All further steps are for registers with local information.
if (ssaRegLocal == null) {
return;
}
- // Record that this SSA reg has been associated with a local
+ // Record that this SSA reg has been associated with a local.
setNameForSsaReg(ssaReg);
- // Ensure that no other SSA regs are associated with this local
+ // Ensure that no other SSA regs are associated with this local.
for (int i = currentMapping.length - 1; i >= 0; i--) {
RegisterSpec cur = currentMapping[i];
@@ -436,7 +438,7 @@
* {@inheritDoc}
*
* Phi insns have their result registers renamed.
- * */
+ */
public void visitPhiInsn(PhiInsn phi) {
/* don't process sources for phi's */
processResultReg(phi);
@@ -452,7 +454,7 @@
*/
public void visitMoveInsn(NormalSsaInsn insn) {
/*
- * for moves: copy propogate the move if we can, but don't
+ * For moves: copy propogate the move if we can, but don't
* if we need to preserve local variable info and the
* result has a different name than the source.
*/
@@ -464,7 +466,8 @@
insn.mapSourceRegisters(mapper);
int ssaSourceReg = insn.getSources().get(0).getReg();
- LocalItem sourceLocal = currentMapping[ropSourceReg].getLocalItem();
+ LocalItem sourceLocal
+ = currentMapping[ropSourceReg].getLocalItem();
LocalItem resultLocal = ropResult.getLocalItem();
/*
@@ -475,25 +478,26 @@
*/
LocalItem newLocal
- = (resultLocal == null) ? sourceLocal : resultLocal;
-
+ = (resultLocal == null) ? sourceLocal : resultLocal;
LocalItem associatedLocal = getLocalForNewReg(ssaSourceReg);
- // If we take the new local, will only one local have ever
- // been associated with this SSA reg?
+ /*
+ * If we take the new local, will only one local have ever
+ * been associated with this SSA reg?
+ */
boolean onlyOneAssociatedLocal
= associatedLocal == null || newLocal == null
|| newLocal.equals(associatedLocal);
-
+
/*
- * If we're going to copy-propogate, then the ssa register spec
- * that's going to go into the mapping is made up of the
- * source register number mapped from above, the type
+ * If we're going to copy-propogate, then the ssa register
+ * spec that's going to go into the mapping is made up of
+ * the source register number mapped from above, the type
* of the result, and the name either from the result (if
* specified) or inherited from the existing mapping.
*
- * The move source has incomplete type information
- * in null object cases, so the result type is used.
+ * The move source has incomplete type information in null
+ * object cases, so the result type is used.
*/
RegisterSpec ssaReg
= RegisterSpec.makeLocalOptional(
@@ -509,15 +513,12 @@
addMapping(ropResultReg, ssaReg);
} else if (onlyOneAssociatedLocal && sourceLocal == null) {
-
/*
* The register was previously unnamed. This means that a
* local starts after it's first assignment in SSA form
*/
- RegisterSpecList ssaSources;
-
- ssaSources = RegisterSpecList.make(
+ RegisterSpecList ssaSources = RegisterSpecList.make(
RegisterSpec.make(ssaReg.getReg(),
ssaReg.getType(), newLocal));
@@ -528,12 +529,12 @@
insnsToReplace.put(insn, newInsn);
- // Just map as above
+ // Just map as above.
addMapping(ropResultReg, ssaReg);
} else {
/*
- * Do not copy-propogate, since the two registers
- * have two different local-variable names
+ * Do not copy-propogate, since the two registers have
+ * two different local-variable names.
*/
processResultReg(insn);
@@ -594,11 +595,12 @@
ropReg = insn.getRopResultReg();
/*
- * Never add a version 0 register as a phi operand.
- * Version 0 registers represent the initial register state,
- * and thus are never significant. Furthermore,
- * the register liveness algorithm doesn't properly
- * count them as "live in" at the beginning of the method.
+ * Never add a version 0 register as a phi
+ * operand. Version 0 registers represent the
+ * initial register state, and thus are never
+ * significant. Furthermore, the register liveness
+ * algorithm doesn't properly count them as "live
+ * in" at the beginning of the method.
*/
RegisterSpec stackTop = currentMapping[ropReg];
@@ -611,9 +613,7 @@
BitSet successors = block.getSuccessors();
for (int i = successors.nextSetBit(0); i >= 0;
i = successors.nextSetBit(i + 1)) {
-
SsaBasicBlock successor = ssaMeth.getBlocks().get(i);
-
successor.forEachPhiInsn(visitor);
}
}
diff --git a/dx/src/com/android/dx/ssa/_tests/_DomFront.java b/dx/src/com/android/dx/ssa/_tests/_DomFront.java
index 997da21..3d891c9 100644
--- a/dx/src/com/android/dx/ssa/_tests/_DomFront.java
+++ b/dx/src/com/android/dx/ssa/_tests/_DomFront.java
@@ -19,7 +19,7 @@
import junit.framework.TestCase;
/**
- * Test the class <code>com.android.dx.ssa.DomFront</code>.
+ * Test the class {@code com.android.dx.ssa.DomFront}.
*/
public class _DomFront
extends TestCase {
diff --git a/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java b/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java
index d3ff7c7..6416e84 100644
--- a/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java
+++ b/dx/src/com/android/dx/ssa/back/FirstFitAllocator.java
@@ -106,7 +106,6 @@
}
for (int j = i + 1; j < oldRegCount; j++) {
-
if (mapped.get(j) || isDefinitionMoveParam(j)) {
continue;
}
diff --git a/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java b/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java
index 14eac90..0cffcfa 100644
--- a/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java
+++ b/dx/src/com/android/dx/ssa/back/FirstFitLocalCombiningAllocator.java
@@ -40,9 +40,10 @@
* kept together if possible.
*/
public class FirstFitLocalCombiningAllocator extends RegisterAllocator {
+ /** local debug flag */
private static final boolean DEBUG = false;
- /** maps local variable to a list of associated SSA registers*/
+ /** maps local variable to a list of associated SSA registers */
private final Map<LocalItem, ArrayList<RegisterSpec>> localVariables;
/** list of move-result-pesudo instructions seen in this method */
@@ -57,29 +58,28 @@
/** Register mapper which will be our result */
private final InterferenceRegisterMapper mapper;
- /** end of rop registers range (starting at 0) reserved for parameters. */
+ /** end of rop registers range (starting at 0) reserved for parameters */
private final int paramRangeEnd;
- /** set of Rop registers reserved for parameters or local variables. */
+ /** set of rop registers reserved for parameters or local variables */
private final BitSet reservedRopRegs;
- /** set of Rop registers that have been used by anything.*/
+ /** set of rop registers that have been used by anything */
private final BitSet usedRopRegs;
- /** true if converter should take steps to minimize rop-form registers*/
+ /** true if converter should take steps to minimize rop-form registers */
private final boolean minimizeRegisters;
-
/**
* Constructs instance.
*
- * @param ssaMeth non-null; method to process
+ * @param ssaMeth {@code non-null;} method to process
* @param interference non-null interference graph for SSA registers
* @param minimizeRegisters true if converter should take steps to
* minimize rop-form registers
*/
public FirstFitLocalCombiningAllocator(
- final SsaMethod ssaMeth, InterferenceGraph interference,
+ SsaMethod ssaMeth, InterferenceGraph interference,
boolean minimizeRegisters) {
super(ssaMeth, interference);
@@ -122,22 +122,24 @@
printLocalVars();
}
- if(DEBUG) System.out.println("--->Mapping local-associated params");
+ if (DEBUG) System.out.println("--->Mapping local-associated params");
handleLocalAssociatedParams();
- if(DEBUG) System.out.println("--->Mapping other params");
+ if (DEBUG) System.out.println("--->Mapping other params");
handleUnassociatedParameters();
- if(DEBUG) System.out.println("--->Mapping invoke-range");
+ if (DEBUG) System.out.println("--->Mapping invoke-range");
handleInvokeRangeInsns();
-
- if(DEBUG) System.out.println("--->Mapping local-associated non-params");
+
+ if (DEBUG) {
+ System.out.println("--->Mapping local-associated non-params");
+ }
handleLocalAssociatedOther();
- if(DEBUG) System.out.println("--->Mapping check-cast results");
+ if (DEBUG) System.out.println("--->Mapping check-cast results");
handleCheckCastResults();
- if(DEBUG) System.out.println("--->Mapping others");
+ if (DEBUG) System.out.println("--->Mapping others");
handleNormalUnassociated();
return mapper;
@@ -148,13 +150,13 @@
*/
private void printLocalVars() {
System.out.println("Printing local vars");
- for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e:
+ for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> e :
localVariables.entrySet()) {
StringBuilder regs = new StringBuilder();
regs.append('{');
regs.append(' ');
- for(RegisterSpec reg: e.getValue()) {
+ for (RegisterSpec reg : e.getValue()) {
regs.append('v');
regs.append(reg.getReg());
regs.append(' ');
@@ -165,16 +167,16 @@
}
/**
- * Maps all local-associated parameters to Rop registers.
+ * Maps all local-associated parameters to rop registers.
*/
private void handleLocalAssociatedParams() {
- for (ArrayList<RegisterSpec> ssaRegs: localVariables.values()) {
+ for (ArrayList<RegisterSpec> ssaRegs : localVariables.values()) {
int sz = ssaRegs.size();
int paramIndex = -1;
int paramCategory = 0;
- // First, find out if this local variable is a parameter
- for (int i = 0 ; i < sz ; i++) {
+ // First, find out if this local variable is a parameter.
+ for (int i = 0; i < sz; i++) {
RegisterSpec ssaSpec = ssaRegs.get(i);
int ssaReg = ssaSpec.getReg();
@@ -188,31 +190,31 @@
}
if (paramIndex < 0) {
- // this local wasn't a parameter
+ // This local wasn't a parameter.
continue;
}
- // Any remaining local-associated registers will be mapped later
+ // Any remaining local-associated registers will be mapped later.
tryMapRegs(ssaRegs, paramIndex, paramCategory, true);
}
}
/**
* Gets the parameter index for SSA registers that are method parameters.
- * -1 is returned for non-parameter registers.
+ * {@code -1} is returned for non-parameter registers.
*
- * @param ssaReg >=0 SSA register to look up
- * @return parameter index or -1 if not a parameter
+ * @param ssaReg {@code >=0;} SSA register to look up
+ * @return parameter index or {@code -1} if not a parameter
*/
private int getParameterIndexForReg(int ssaReg) {
SsaInsn defInsn = ssaMeth.getDefinitionForRegister(ssaReg);
if (defInsn == null) {
return -1;
}
-
+
Rop opcode = defInsn.getOpcode();
- // opcode == null for phi insns
+ // opcode == null for phi insns.
if (opcode != null && opcode.getOpcode() == RegOps.MOVE_PARAM) {
CstInsn origInsn = (CstInsn) defInsn.getOriginalRopInsn();
return ((CstInteger) origInsn.getConstant()).getValue();
@@ -222,20 +224,21 @@
}
/**
- * Maps all local-associated registers that are not parameters. Tries to
- * find an unreserved range that's wide enough for all of the SSA registers,
- * and then tries to map them all to that range. If not all fit,
- * a new range is tried until all registers have been fit.
+ * Maps all local-associated registers that are not parameters.
+ * Tries to find an unreserved range that's wide enough for all of
+ * the SSA registers, and then tries to map them all to that
+ * range. If not all fit, a new range is tried until all registers
+ * have been fit.
*/
private void handleLocalAssociatedOther() {
- for (ArrayList<RegisterSpec> specs: localVariables.values()) {
+ for (ArrayList<RegisterSpec> specs : localVariables.values()) {
int ropReg = 0;
boolean done;
do {
int maxCategory = 1;
- // compute max category for remaining unmapped registers
+ // Compute max category for remaining unmapped registers.
int sz = specs.size();
for (int i = 0; i < sz; i++) {
RegisterSpec ssaSpec = specs.get(i);
@@ -250,7 +253,7 @@
done = tryMapRegs(specs, ropReg, maxCategory, true);
- // Increment for next call to findNext
+ // Increment for next call to findNext.
ropReg++;
} while (!done);
}
@@ -261,17 +264,19 @@
* used rop space as reserved. SSA registers that don't fit are left
* unmapped.
*
- * @param specs non-null; SSA registers to attempt to map
- * @param ropReg >=0 rop register to map to
- * @param maxAllowedCategory 1 or 2, maximum category allowed in mapping.
- * @param markReserved do so if true
- * @return true if all registers wew mapped, false if some remain unmapped.
+ * @param specs {@code non-null;} SSA registers to attempt to map
+ * @param ropReg {@code >=0;} rop register to map to
+ * @param maxAllowedCategory {@code 1..2;} maximum category
+ * allowed in mapping.
+ * @param markReserved do so if {@code true}
+ * @return {@code true} if all registers were mapped, {@code false}
+ * if some remain unmapped
*/
private boolean tryMapRegs(
ArrayList<RegisterSpec> specs, int ropReg,
int maxAllowedCategory, boolean markReserved) {
boolean remaining = false;
- for(RegisterSpec spec: specs) {
+ for (RegisterSpec spec : specs) {
if (ssaRegsMapped.get(spec.getReg())) {
continue;
}
@@ -291,11 +296,11 @@
/**
* Tries to map an SSA register to a rop register.
*
- * @param ssaSpec non-null; SSA register
- * @param ropReg >=0 rop register
- * @param maxAllowedCategory 1 or 2, the maximum category that the SSA
- * register is allowed to be.
- * @return true if map succeeded, false if not.
+ * @param ssaSpec {@code non-null;} SSA register
+ * @param ropReg {@code >=0;} rop register
+ * @param maxAllowedCategory {@code 1..2;} the maximum category
+ * that the SSA register is allowed to be
+ * @return {@code true} if map succeeded, {@code false} if not
*/
private boolean tryMapReg(RegisterSpec ssaSpec, int ropReg,
int maxAllowedCategory) {
@@ -310,22 +315,22 @@
}
/**
- * Marks a range of Rop registers as "reserved for a local variable"
+ * Marks a range of rop registers as "reserved for a local variable."
*
- * @param ropReg >= 0 rop register to reserve
- * @param category > 0 width to reserve
+ * @param ropReg {@code >= 0;} rop register to reserve
+ * @param category {@code > 0;} width to reserve
*/
private void markReserved(int ropReg, int category) {
reservedRopRegs.set(ropReg, ropReg + category, true);
}
/**
- * Checks to see if any Rop registers in the specified range are reserved
- * for local variables or parameters
+ * Checks to see if any rop registers in the specified range are reserved
+ * for local variables or parameters.
*
- * @param ropRangeStart >= 0 lowest Rop register
- * @param width > 0 number of Rop registers in range.
- * @return true if any register in range is marked reserved
+ * @param ropRangeStart {@code >= 0;} lowest rop register
+ * @param width {@code > 0;} number of rop registers in range.
+ * @return {@code true} if any register in range is marked reserved
*/
private boolean rangeContainsReserved(int ropRangeStart, int width) {
for (int i = ropRangeStart; i < (ropRangeStart + width); i++) {
@@ -337,23 +342,23 @@
}
/**
- * Returns true if given rop register represents the "this" pointer
- * for a non-static method
+ * Returns true if given rop register represents the {@code this} pointer
+ * for a non-static method.
*
* @param startReg rop register
* @return true if the "this" pointer is located here.
*/
private boolean isThisPointerReg(int startReg) {
- // "this" is always the first parameter
+ // "this" is always the first parameter.
return startReg == 0 && !ssaMeth.isStatic();
}
/**
- * Finds a range of unreserved Rop registers.
+ * Finds a range of unreserved rop registers.
*
- * @param startReg >= 0; a Rop register to start the search at
- * @param width > 0; the width, in registers, required.
- * @return >= 0; start of available register range.
+ * @param startReg {@code >= 0;} a rop register to start the search at
+ * @param width {@code > 0;} the width, in registers, required.
+ * @return {@code >= 0;} start of available register range.
*/
private int findNextUnreservedRopReg(int startReg, int width) {
if (minimizeRegisters && !isThisPointerReg(startReg)) {
@@ -381,12 +386,12 @@
/**
* Finds a range of rop regs that can be used for local variables.
- * If <code>MIX_LOCALS_AND_OTHER</code> is false, this means any
+ * If {@code MIX_LOCALS_AND_OTHER} is {@code false}, this means any
* rop register that has not yet been used.
*
- * @param startReg >= 0; a Rop register to start the search at
- * @param width > 0; the width, in registers, required.
- * @return >= 0; start of available register range.
+ * @param startReg {@code >= 0;} a rop register to start the search at
+ * @param width {@code > 0;} the width, in registers, required.
+ * @return {@code >= 0;} start of available register range.
*/
private int findRopRegForLocal(int startReg, int width) {
if (minimizeRegisters && !isThisPointerReg(startReg)) {
@@ -418,6 +423,7 @@
*/
private void handleUnassociatedParameters() {
int szSsaRegs = ssaMeth.getRegCount();
+
for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
if (ssaRegsMapped.get(ssaReg)) {
// We already did this one above
@@ -429,7 +435,7 @@
RegisterSpec ssaSpec = getDefinitionSpecForSsaReg(ssaReg);
if (paramIndex >= 0) {
addMapping(ssaSpec, paramIndex);
- }
+ }
}
}
@@ -437,13 +443,14 @@
* Handles all insns that want a register range for their sources.
*/
private void handleInvokeRangeInsns() {
- for(NormalSsaInsn insn: invokeRangeInsns) {
+ for (NormalSsaInsn insn : invokeRangeInsns) {
adjustAndMapSourceRangeRange(insn);
}
}
/**
- * Handles check cast results to reuse the same source register if possible
+ * Handles check cast results to reuse the same source register if
+ * possible.
*/
private void handleCheckCastResults() {
for (NormalSsaInsn insn : moveResultPseudoInsns) {
@@ -498,11 +505,11 @@
}
/**
- * Maps all non-parameter, non-local variable
- * registers.
+ * Maps all non-parameter, non-local variable registers.
*/
private void handleNormalUnassociated() {
int szSsaRegs = ssaMeth.getRegCount();
+
for (int ssaReg = 0; ssaReg < szSsaRegs; ssaReg++) {
if (ssaRegsMapped.get(ssaReg)) {
// We already did this one
@@ -525,30 +532,30 @@
}
/**
- * Checks to see if <code>ssaSpec</code> can be mapped to
- * <code>ropReg</code>. Checks interference graph and ensures
+ * Checks to see if {@code ssaSpec} can be mapped to
+ * {@code ropReg}. Checks interference graph and ensures
* the range does not cross the parameter range.
*
- * @param ssaSpec non-null; SSA spec
+ * @param ssaSpec {@code non-null;} SSA spec
* @param ropReg prosepctive new-namespace reg
- * @return true if mapping is possible
+ * @return {@code true} if mapping is possible
*/
private boolean canMapReg(RegisterSpec ssaSpec, int ropReg) {
int category = ssaSpec.getCategory();
return !(spansParamRange(ropReg, category)
|| mapper.interferes(ssaSpec, ropReg));
}
-
+
/**
- * Returns true if the specified Rop register + category
- * will cross the boundry between the lower <code>paramWidth</code>
+ * Returns true if the specified rop register + category
+ * will cross the boundry between the lower {@code paramWidth}
* registers reserved for method params and the upper registers. We cannot
* allocate a register that spans the param block and the normal block,
* because we will be moving the param block to high registers later.
- *
+ *
* @param ssaReg register in new namespace
* @param category width that the register will have
- * @return true in the case noted above.
+ * @return {@code true} in the case noted above
*/
private boolean spansParamRange(int ssaReg, int category) {
return ((ssaReg < paramRangeEnd)
@@ -561,7 +568,6 @@
*/
private void analyzeInstructions() {
ssaMeth.forEachInsn(new SsaInsn.Visitor() {
-
/** {@inheritDoc} */
public void visitMoveInsn(NormalSsaInsn insn) {
processInsn(insn);
@@ -579,15 +585,16 @@
/**
* This method collects three types of instructions:
- * 1) Adds a local variable assignment to the
- * <code>localVariables</code> map.
- * 2) Add move-result-pseudo to the
- * <code>moveResultPseudoInsns</code> list.
- * 3) Add invoke-range to the
- * <code>invokeRangeInsns</code> list.
*
- * @param insn non-null; insn that may represent a local variable
- * assignment.
+ * 1) Adds a local variable assignment to the
+ * {@code localVariables} map.
+ * 2) Add move-result-pseudo to the
+ * {@code moveResultPseudoInsns} list.
+ * 3) Add invoke-range to the
+ * {@code invokeRangeInsns} list.
+ *
+ * @param insn {@code non-null;} insn that may represent a
+ * local variable assignment
*/
private void processInsn(SsaInsn insn) {
RegisterSpec assignment;
@@ -596,7 +603,8 @@
if (assignment != null) {
LocalItem local = assignment.getLocalItem();
- ArrayList<RegisterSpec> regList = localVariables.get(local);
+ ArrayList<RegisterSpec> regList
+ = localVariables.get(local);
if (regList == null) {
regList = new ArrayList<RegisterSpec>();
@@ -622,16 +630,16 @@
}
/**
- * Adds a mapping from an SSA register to a Rop register. <code>
- * canMapReg</code> should have already been called.
+ * Adds a mapping from an SSA register to a rop register.
+ * {@link #canMapReg} should have already been called.
*
- * @param ssaSpec non-null; SSA register to map from
- * @param ropReg >=0; Rop register to map to
+ * @param ssaSpec {@code non-null;} SSA register to map from
+ * @param ropReg {@code >=0;} rop register to map to
*/
private void addMapping(RegisterSpec ssaSpec, int ropReg) {
int ssaReg = ssaSpec.getReg();
- // An assertion
+ // An assertion.
if (ssaRegsMapped.get(ssaReg) || !canMapReg(ssaSpec, ropReg)) {
throw new RuntimeException(
"attempt to add invalid register mapping");
@@ -639,8 +647,7 @@
if (DEBUG) {
System.out.printf("Add mapping s%d -> v%d c:%d\n",
- ssaSpec.getReg(), ropReg, ssaSpec.getCategory());
-
+ ssaSpec.getReg(), ropReg, ssaSpec.getCategory());
}
int category = ssaSpec.getCategory();
@@ -652,19 +659,18 @@
/**
* Maps the source registers of the specified instruction such that they
- * will fall in a contiguous range in Rop form. Moves are inserted as
+ * will fall in a contiguous range in rop form. Moves are inserted as
* necessary to allow the range to be allocated.
*
- * @param insn non-null; insn whos sources to process
+ * @param insn {@code non-null;} insn whos sources to process
*/
private void adjustAndMapSourceRangeRange(NormalSsaInsn insn) {
- int newRegStart;
-
- newRegStart = findRangeAndAdjust(insn);
+ int newRegStart = findRangeAndAdjust(insn);
RegisterSpecList sources = insn.getSources();
int szSources = sources.size();
int nextRopReg = newRegStart;
+
for (int i = 0; i < szSources; i++) {
RegisterSpec source = sources.get(i);
int sourceReg = source.getReg();
@@ -686,17 +692,20 @@
int szSimilar = similarRegisters.size();
- // Try to map all SSA registers also associated with this local
+ /*
+ * Try to map all SSA registers also associated with
+ * this local.
+ */
for (int j = 0; j < szSimilar; j++) {
RegisterSpec similarSpec = similarRegisters.get(j);
int similarReg = similarSpec.getReg();
- // ...and don't map anything that's also a source...
+ // Don't map anything that's also a source.
if (-1 != sources.indexOfRegister(similarReg)) {
continue;
}
- // Registers left unmapped will get handled later
+ // Registers left unmapped will get handled later.
tryMapReg(similarSpec, curRopReg, category);
}
}
@@ -706,12 +715,12 @@
/**
* Find a contiguous rop register range that fits the specified
* instruction's sources. First, try to center the range around
- * sources that have already been mapped to Rop registers. If that fails,
+ * sources that have already been mapped to rop registers. If that fails,
* just find a new contiguous range that doesn't interfere.
-
- * @param insn non-null; the insn whose sources need to fit. Must be
- * last insn in basic block.
- * @return >= 0 rop register of start of range
+ *
+ * @param insn {@code non-null;} the insn whose sources need to
+ * fit. Must be last insn in basic block.
+ * @return {@code >= 0;} rop register of start of range
*/
private int findRangeAndAdjust(NormalSsaInsn insn) {
RegisterSpecList sources = insn.getSources();
@@ -727,7 +736,7 @@
rangeLength += categoriesForIndex[i];
}
- // The highest score of fits tried so far
+ // the highest score of fits tried so far
int maxScore = Integer.MIN_VALUE;
// the high scoring range's start
int resultRangeStart = -1;
@@ -736,7 +745,7 @@
/*
* First, go through each source that's already been mapped. Try
- * to center the range around the Rop register this source is mapped
+ * to center the range around the rop register this source is mapped
* to.
*/
int rangeStartOffset = 0;
@@ -794,13 +803,12 @@
}
/*
- * Now, insert any moves required
+ * Now, insert any moves required.
*/
- for (int i = resultMovesRequired.nextSetBit(0); i >= 0
- ; i = resultMovesRequired.nextSetBit(i+1)) {
- insn.changeOneSource(i,
- insertMoveBefore(insn, sources.get(i)));
+ for (int i = resultMovesRequired.nextSetBit(0); i >= 0;
+ i = resultMovesRequired.nextSetBit(i+1)) {
+ insn.changeOneSource(i, insertMoveBefore(insn, sources.get(i)));
}
return resultRangeStart;
@@ -811,14 +819,14 @@
* specified instruction. Does not bother trying to center the range
* around an already-mapped source register;
*
- * @param insn non-null; insn to build range for
- * @param rangeLength >=0 length required in register units.
- * @param categoriesForIndex non-null; indexed by source index;
- * the category for each source.
- * @param outMovesRequired non-null; an output parameter indexed by
+ * @param insn {@code non-null;} insn to build range for
+ * @param rangeLength {@code >=0;} length required in register units
+ * @param categoriesForIndex {@code non-null;} indexed by source index;
+ * the category for each source
+ * @param outMovesRequired {@code non-null;} an output parameter indexed by
* source index that will contain the set of sources which need
- * moves inserted.
- * @return the rop register that starts the fitting range.
+ * moves inserted
+ * @return the rop register that starts the fitting range
*/
private int findAnyFittingRange(NormalSsaInsn insn, int rangeLength,
int[] categoriesForIndex, BitSet outMovesRequired) {
@@ -842,15 +850,15 @@
* Attempts to build a plan for fitting a range of sources into rop
* registers.
*
- * @param ropReg >=0 rop reg that begins range
- * @param insn non-null; insn to plan range for
- * @param categoriesForIndex non-null; indexed by source index;
- * the category for each source.
- * @param outMovesRequired non-null; an output parameter indexed by
+ * @param ropReg {@code >= 0;} rop reg that begins range
+ * @param insn {@code non-null;} insn to plan range for
+ * @param categoriesForIndex {@code non-null;} indexed by source index;
+ * the category for each source
+ * @param outMovesRequired {@code non-null;} an output parameter indexed by
* source index that will contain the set of sources which need
- * moves inserted.
+ * moves inserted
* @return the width of the fit that that does not involve added moves or
- * -1 if "no fit possible"
+ * {@code -1} if "no fit possible"
*/
private int fitPlanForRange(int ropReg, NormalSsaInsn insn,
int[] categoriesForIndex, BitSet outMovesRequired) {
@@ -860,7 +868,7 @@
IntSet liveOut = insn.getBlock().getLiveOutRegs();
RegisterSpecList liveOutSpecs = ssaSetToSpecs(liveOut);
- // An SSA reg may only be mapped into a range once
+ // An SSA reg may only be mapped into a range once.
BitSet seen = new BitSet(ssaMeth.getRegCount());
for (int i = 0; i < szSources ; i++) {
@@ -874,7 +882,7 @@
if (ssaRegsMapped.get(ssaReg)
&& mapper.oldToNew(ssaReg) == ropReg) {
- // A register already mapped appropriately
+ // This is a register that is already mapped appropriately.
fitWidth += category;
} else if (rangeContainsReserved(ropReg, category)) {
fitWidth = -1;
@@ -882,19 +890,20 @@
} else if (!ssaRegsMapped.get(ssaReg)
&& canMapReg(ssaSpec, ropReg)
&& !seen.get(ssaReg)) {
- // A register that can be mapped appropriately
+ // This is a register that can be mapped appropriately.
fitWidth += category;
} else if (!mapper.areAnyPinned(liveOutSpecs, ropReg, category)
&& !mapper.areAnyPinned(sources, ropReg, category)) {
/*
- * A source that can be moved
- * We can insert a move as long as:
+ * This is a source that can be moved. We can insert a
+ * move as long as:
*
- * - no SSA register pinned to the desired rop reg
- * is live out on the block
- * - no SSA register pinned to desired rop reg is
- * a source of this insn (since this may require
- * overlapping moves, which we can't presently handle)
+ * * no SSA register pinned to the desired rop reg
+ * is live out on the block
+ *
+ * * no SSA register pinned to desired rop reg is
+ * a source of this insn (since this may require
+ * overlapping moves, which we can't presently handle)
*/
outMovesRequired.set(i);
@@ -912,7 +921,7 @@
* Converts a bit set of SSA registers into a RegisterSpecList containing
* the definition specs of all the registers.
*
- * @param ssaSet non-null; set of SSA registers
+ * @param ssaSet {@code non-null;} set of SSA registers
* @return list of RegisterSpecs as noted above
*/
RegisterSpecList ssaSetToSpecs(IntSet ssaSet) {
@@ -924,21 +933,20 @@
while (iter.hasNext()) {
result.set(i++, getDefinitionSpecForSsaReg(iter.next()));
}
-
+
return result;
}
/**
- * Gets a local item associated with an ssa register, if one exists
+ * Gets a local item associated with an ssa register, if one exists.
*
- * @param ssaReg >= 0 SSA register
- * @return null-ok; associated local item or null
+ * @param ssaReg {@code >= 0;} SSA register
+ * @return {@code null-ok;} associated local item or null
*/
private LocalItem getLocalItemForReg(int ssaReg) {
- for(Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry:
- localVariables.entrySet()) {
-
- for (RegisterSpec spec: entry.getValue()) {
+ for (Map.Entry<LocalItem, ArrayList<RegisterSpec>> entry :
+ localVariables.entrySet()) {
+ for (RegisterSpec spec : entry.getValue()) {
if (spec.getReg() == ssaReg) {
return entry.getKey();
}
diff --git a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
index abc5fca..a639af5 100644
--- a/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
+++ b/dx/src/com/android/dx/ssa/back/IdenticalBlockCombiner.java
@@ -34,14 +34,14 @@
* frequently are created when catch blocks are edge-split.
*/
public class IdenticalBlockCombiner {
-
- private RopMethod ropMethod;
- private BasicBlockList blocks;
- private BasicBlockList newBlocks;
+ private final RopMethod ropMethod;
+ private final BasicBlockList blocks;
+ private final BasicBlockList newBlocks;
/**
- * Constructs instance. Call <code>process()</code> to run.
- * @param rm instance to process
+ * Constructs instance. Call {@code process()} to run.
+ *
+ * @param rm {@code non-null;} instance to process
*/
public IdenticalBlockCombiner(RopMethod rm) {
ropMethod = rm;
@@ -50,10 +50,11 @@
}
/**
- * Runs algorithm. TODO: this is n^2, and could be made linear-ish with
- * a hash.
+ * Runs algorithm. TODO: This is n^2, and could be made linear-ish with
+ * a hash. In particular, hash the contents of each block and only
+ * compare blocks with the same hash.
*
- * @return new method that has been processed
+ * @return {@code non-null;} new method that has been processed
*/
public RopMethod process() {
int szBlocks = blocks.size();
@@ -78,14 +79,15 @@
BasicBlock iBlock = blocks.labelToBlock(iLabel);
- if (toDelete.get(iLabel) || iBlock.getSuccessors().size() > 1) {
+ if (toDelete.get(iLabel)
+ || iBlock.getSuccessors().size() > 1) {
continue;
}
IntList toCombine = new IntList();
// ...and see if they can be combined with any other preds...
- for (int j = i + 1; j <szPreds; j++) {
+ for (int j = i + 1; j < szPreds; j++) {
int jLabel = preds.get(j);
BasicBlock jBlock = blocks.labelToBlock(jLabel);
@@ -101,7 +103,7 @@
}
}
- for (int i = szBlocks - 1; i > 0; i--) {
+ for (int i = szBlocks - 1; i >= 0; i--) {
if (toDelete.get(newBlocks.get(i).getLabel())) {
newBlocks.set(i, null);
}
@@ -113,7 +115,14 @@
return new RopMethod(newBlocks, ropMethod.getFirstLabel());
}
- private boolean compareInsns(BasicBlock a, BasicBlock b) {
+ /**
+ * 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
+ */
+ private static boolean compareInsns(BasicBlock a, BasicBlock b) {
return a.getInsns().contentEquals(b.getInsns());
}
@@ -131,11 +140,7 @@
for (int i = 0; i < szBetas; i++) {
int betaLabel = betaLabels.get(i);
BasicBlock bb = blocks.labelToBlock(betaLabel);
-
- IntList preds;
-
- preds = ropMethod.labelToPredecessors(bb.getLabel());
-
+ IntList preds = ropMethod.labelToPredecessors(bb.getLabel());
int szPreds = preds.size();
for (int j = 0; j < szPreds; j++) {
@@ -147,19 +152,19 @@
/**
* Replaces one of a block's successors with a different label. Constructs
- * an updated BasicBlock instance and places it in <code>newBlocks</code>.
+ * an updated BasicBlock instance and places it in {@code newBlocks}.
*
* @param block block to replace
* @param oldLabel label of successor to replace
* @param newLabel label of new successor
*/
private void replaceSucc(BasicBlock block, int oldLabel, int newLabel) {
-
IntList newSuccessors = block.getSuccessors().mutableCopy();
int newPrimarySuccessor;
newSuccessors.set(newSuccessors.indexOf(oldLabel), newLabel);
newPrimarySuccessor = block.getPrimarySuccessor();
+
if (newPrimarySuccessor == oldLabel) {
newPrimarySuccessor = newLabel;
}
diff --git a/dx/src/com/android/dx/ssa/back/InterferenceGraph.java b/dx/src/com/android/dx/ssa/back/InterferenceGraph.java
index 282420b..e6cde62 100644
--- a/dx/src/com/android/dx/ssa/back/InterferenceGraph.java
+++ b/dx/src/com/android/dx/ssa/back/InterferenceGraph.java
@@ -34,14 +34,17 @@
* A register interference graph
*/
public class InterferenceGraph {
- /** interference graph, indexed by register in both dimensions */
+ /**
+ * {@code non-null;} interference graph, indexed by register in
+ * both dimensions
+ */
private final ArrayList<IntSet> interference;
/**
* Creates a new graph.
*
- * @param countRegs >=0 the start count of registers in the namespace.
- * New registers can be added subsequently.
+ * @param countRegs {@code >= 0;} the start count of registers in
+ * the namespace. New registers can be added subsequently.
*/
public InterferenceGraph(int countRegs) {
interference = new ArrayList<IntSet>(countRegs);
@@ -83,9 +86,9 @@
/**
* Merges the interference set for a register into a given bit set
*
- * @param reg >=0 register
- * @param set non-null; interference set; will be merged with set for
- * given register
+ * @param reg {@code >= 0;} register
+ * @param set {@code non-null;} interference set; will be merged
+ * with set for given register
*/
public void mergeInterferenceSet(int reg, IntSet set) {
if (reg < interference.size()) {
@@ -100,8 +103,10 @@
*/
private void ensureCapacity(int size) {
int countRegs = interference.size();
+
interference.ensureCapacity(size);
- for (int i = countRegs ; i < size; i++) {
+
+ for (int i = countRegs; i < size; i++) {
interference.add(SetFactory.makeInterferenceSet(size));
}
}
diff --git a/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java b/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
index 5ae6e07..cd3f7d2 100644
--- a/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
+++ b/dx/src/com/android/dx/ssa/back/LivenessAnalyzer.java
@@ -28,28 +28,27 @@
/**
* From Appel "Modern Compiler Implementation in Java" algorithm 19.17
- * Calculate the live ranges for register <code>reg</code>.<p>
+ * Calculate the live ranges for register {@code reg}.<p>
*
* v = regV <p>
* s = insn <p>
* M = visitedBlocks <p>
*/
public class LivenessAnalyzer {
-
/**
- * non-null; index by basic block indexed set of basic blocks
+ * {@code non-null;} index by basic block indexed set of basic blocks
* that have already been visited. "M" as written in the original Appel
* algorithm.
*/
private final BitSet visitedBlocks;
/**
- * non-null; set of blocks remaing to visit as "live out as block"
+ * {@code non-null;} set of blocks remaing to visit as "live out as block"
*/
private final BitSet liveOutBlocks;
/**
- * >=0; SSA register currently being analyzed.
+ * {@code >=0;} SSA register currently being analyzed.
* "v" in the original Appel algorithm.
*/
private final int regV;
@@ -61,33 +60,34 @@
private final InterferenceGraph interference;
/** block "n" in Appel 19.17 */
- SsaBasicBlock blockN;
+ private SsaBasicBlock blockN;
- /** index of statement <code>s</code> in <code>blockN</code>*/
+ /** index of statement {@code s} in {@code blockN} */
private int statementIndex;
- /** the next function to call. one of the four constants below */
- private int nextFunction;
+ /** the next function to call */
+ private NextFunction nextFunction;
- /** constants for nextFunction */
- static final int LIVE_IN_AT_STATEMENT = 1;
- static final int LIVE_OUT_AT_STATEMENT = 2;
- static final int LIVE_OUT_AT_BLOCK = 3;
- static final int DONE = 4;
+ /** constants for {@link #nextFunction} */
+ private static enum NextFunction {
+ LIVE_IN_AT_STATEMENT,
+ LIVE_OUT_AT_STATEMENT,
+ LIVE_OUT_AT_BLOCK,
+ DONE;
+ }
/**
* Runs register liveness algorithm for a method, updating the
- * live in/out information in <code>SsaBasicBlock</code> instances and
+ * live in/out information in {@code SsaBasicBlock} instances and
* returning an interference graph.
*
- * @param ssaMeth non-null; Method to process.
- * @return non-null; interference graph indexed by SSA registers in both
- * directions.
+ * @param ssaMeth {@code non-null;} method to process
+ * @return {@code non-null;} interference graph indexed by SSA
+ * registers in both directions
*/
public static InterferenceGraph constructInterferenceGraph(
SsaMethod ssaMeth) {
int szRegs = ssaMeth.getRegCount();
-
InterferenceGraph interference = new InterferenceGraph(szRegs);
for (int i = 0; i < szRegs; i++) {
@@ -102,42 +102,43 @@
/**
* Makes liveness analyzer instance for specific register.
*
- * @param ssaMeth non-null; method to process
+ * @param ssaMeth {@code non-null;} method to process
* @param reg register whose liveness to analyze
- * @param interference non-null; indexed by SSA reg in both dimensions;
- * graph to update
+ * @param interference {@code non-null;} indexed by SSA reg in
+ * both dimensions; graph to update
*
*/
- private LivenessAnalyzer(final SsaMethod ssaMeth, final int reg,
+ private LivenessAnalyzer(SsaMethod ssaMeth, int reg,
InterferenceGraph interference) {
+ int blocksSz = ssaMeth.getBlocks().size();
+
this.ssaMeth = ssaMeth;
this.regV = reg;
- visitedBlocks = new BitSet(ssaMeth.getBlocks().size());
- liveOutBlocks = new BitSet(ssaMeth.getBlocks().size());
+ visitedBlocks = new BitSet(blocksSz);
+ liveOutBlocks = new BitSet(blocksSz);
this.interference = interference;
}
/**
- * The algorithm in Appel is presented in
- * partial tail-recursion form. Obviously, that's not
- * efficient in java, so this function serves
- * as the dispatcher instead.
+ * The algorithm in Appel is presented in partial tail-recursion
+ * form. Obviously, that's not efficient in java, so this function
+ * serves as the dispatcher instead.
*/
private void handleTailRecursion() {
- while (nextFunction != DONE) {
+ while (nextFunction != NextFunction.DONE) {
switch (nextFunction) {
case LIVE_IN_AT_STATEMENT:
- nextFunction = DONE;
+ nextFunction = NextFunction.DONE;
liveInAtStatement();
break;
case LIVE_OUT_AT_STATEMENT:
- nextFunction = DONE;
+ nextFunction = NextFunction.DONE;
liveOutAtStatement();
break;
case LIVE_OUT_AT_BLOCK:
- nextFunction = DONE;
+ nextFunction = NextFunction.DONE;
liveOutAtBlock();
break;
@@ -147,23 +148,23 @@
}
/**
- * From Appel algorithm 19.17
+ * From Appel algorithm 19.17.
*/
public void run() {
List<SsaInsn> useList = ssaMeth.getUseListForRegister(regV);
- for (SsaInsn insn: useList) {
- nextFunction = DONE;
+ for (SsaInsn insn : useList) {
+ nextFunction = NextFunction.DONE;
if (insn instanceof PhiInsn) {
- // If s is a phi-function with V as it's ith argument
+ // If s is a phi-function with V as it's ith argument.
PhiInsn phi = (PhiInsn) insn;
- for (SsaBasicBlock pred: phi.predBlocksForReg(regV, ssaMeth)) {
-
+ for (SsaBasicBlock pred :
+ phi.predBlocksForReg(regV, ssaMeth)) {
blockN = pred;
- nextFunction = LIVE_OUT_AT_BLOCK;
+ nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
handleTailRecursion();
}
} else {
@@ -175,7 +176,7 @@
"insn not found in it's own block");
}
- nextFunction = LIVE_IN_AT_STATEMENT;
+ nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
handleTailRecursion();
}
}
@@ -184,13 +185,13 @@
while ((nextLiveOutBlock = liveOutBlocks.nextSetBit(0)) >= 0) {
blockN = ssaMeth.getBlocks().get(nextLiveOutBlock);
liveOutBlocks.clear(nextLiveOutBlock);
- nextFunction = LIVE_OUT_AT_BLOCK;
+ nextFunction = NextFunction.LIVE_OUT_AT_BLOCK;
handleTailRecursion();
}
}
/**
- * "v is live-out at n"
+ * "v is live-out at n."
*/
private void liveOutAtBlock() {
if (! visitedBlocks.get(blockN.getIndex())) {
@@ -204,15 +205,14 @@
// Live out at last statement in blockN
statementIndex = insns.size() - 1;
- nextFunction = LIVE_OUT_AT_STATEMENT;
+ nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
}
}
/**
- * "v is live-in at s"
+ * "v is live-in at s."
*/
private void liveInAtStatement() {
-
// if s is the first statement in block N
if (statementIndex == 0) {
// v is live-in at n
@@ -224,23 +224,22 @@
} else {
// Let s' be the statement preceeding s
statementIndex -= 1;
- nextFunction = LIVE_OUT_AT_STATEMENT;
+ nextFunction = NextFunction.LIVE_OUT_AT_STATEMENT;
}
}
/**
- * "v is live-out at s"
+ * "v is live-out at s."
*/
private void liveOutAtStatement() {
-
SsaInsn statement = blockN.getInsns().get(statementIndex);
RegisterSpec rs = statement.getResult();
if (!statement.isResultReg(regV)) {
- if(rs != null) {
+ if (rs != null) {
interference.add(regV, rs.getReg());
}
- nextFunction = LIVE_IN_AT_STATEMENT;
+ nextFunction = NextFunction.LIVE_IN_AT_STATEMENT;
}
}
@@ -253,12 +252,12 @@
* as the result of another phi, and the phi removal move scheduler may
* generate moves that over-write the live result.
*
- * @param ssaMeth non-null; method to pricess
- * @param interference non-null; interference graph
+ * @param ssaMeth {@code non-null;} method to pricess
+ * @param interference {@code non-null;} interference graph
*/
private static void coInterferePhis(SsaMethod ssaMeth,
InterferenceGraph interference) {
- for (SsaBasicBlock b: ssaMeth.getBlocks()) {
+ for (SsaBasicBlock b : ssaMeth.getBlocks()) {
List<SsaInsn> phis = b.getPhiInsns();
int szPhis = phis.size();
diff --git a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
index cd3b2f1..f6dc961 100644
--- a/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
+++ b/dx/src/com/android/dx/ssa/back/NullRegisterAllocator.java
@@ -29,11 +29,9 @@
* about normal or wide categories. Used for debugging.
*/
public class NullRegisterAllocator extends RegisterAllocator {
-
/** {@inheritDoc} */
- public NullRegisterAllocator(
- final SsaMethod ssaMeth, final InterferenceGraph interference) {
-
+ public NullRegisterAllocator(SsaMethod ssaMeth,
+ InterferenceGraph interference) {
super(ssaMeth, interference);
}
@@ -49,8 +47,7 @@
public RegisterMapper allocateRegisters() {
int oldRegCount = ssaMeth.getRegCount();
- BasicRegisterMapper mapper
- = new BasicRegisterMapper(oldRegCount);
+ BasicRegisterMapper mapper = new BasicRegisterMapper(oldRegCount);
for (int i = 0; i < oldRegCount; i++) {
mapper.addMapping(i, i*2, 2);
diff --git a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
index 764b03a..e75eee1 100644
--- a/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
+++ b/dx/src/com/android/dx/ssa/back/RegisterAllocator.java
@@ -34,10 +34,9 @@
import java.util.ArrayList;
/**
- * Base class of all register allocators
+ * Base class of all register allocators.
*/
public abstract class RegisterAllocator {
-
/** method being processed */
protected final SsaMethod ssaMeth;
@@ -45,13 +44,13 @@
protected final InterferenceGraph interference;
/**
- * Creates an instance. Call <code>allocateRegisters</code> to run.
+ * Creates an instance. Call {@code allocateRegisters} to run.
* @param ssaMeth method to process.
* @param interference Interference graph, indexed by register in both
* dimensions.
*/
- public RegisterAllocator(
- final SsaMethod ssaMeth, final InterferenceGraph interference) {
+ public RegisterAllocator(SsaMethod ssaMeth,
+ InterferenceGraph interference) {
this.ssaMeth = ssaMeth;
this.interference = interference;
}
@@ -61,26 +60,26 @@
* of the namespace, and thus should be moved up to the top of the
* namespace after phi removal.
*
- * @return true if params should be moved from low to high.
+ * @return {@code true} if params should be moved from low to high
*/
public abstract boolean wantsParamsMovedHigh();
/**
* Runs the algorithm.
- * @return a register mapper to apply to the <code>SsaMethod</code>
+ *
+ * @return a register mapper to apply to the {@code SsaMethod}
*/
public abstract RegisterMapper allocateRegisters();
/**
* Returns the category (width) of the definition site of the register.
- * Returns 1 for undefined registers.
+ * Returns {@code 1} for undefined registers.
*
* @param reg register
- * @return 1 or 2
+ * @return {@code 1..2}
*/
- protected int getCategoryForSsaReg(int reg) {
- SsaInsn definition;
- definition = ssaMeth.getDefinitionForRegister(reg);
+ protected final int getCategoryForSsaReg(int reg) {
+ SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
if (definition == null) {
// an undefined reg
@@ -93,25 +92,26 @@
/**
* Returns the RegisterSpec of the definition of the register.
*
- * @param reg >= 0 SSA register
+ * @param reg {@code >= 0;} SSA register
* @return definition spec of the register or null if it is never defined
- * (for the case of "version 0" SSA registers).
+ * (for the case of "version 0" SSA registers)
*/
- protected RegisterSpec getDefinitionSpecForSsaReg(int reg) {
- SsaInsn definition;
- definition = ssaMeth.getDefinitionForRegister(reg);
+ protected final RegisterSpec getDefinitionSpecForSsaReg(int reg) {
+ SsaInsn definition = ssaMeth.getDefinitionForRegister(reg);
return definition == null ? null : definition.getResult();
}
/**
* Returns true if the definition site of this register is a
- * move-param (ie, this is a method parameter)
+ * move-param (ie, this is a method parameter).
+ *
* @param reg register in question
- * @return true if this is a method parameter
+ * @return {@code true} if this is a method parameter
*/
protected boolean isDefinitionMoveParam(int reg) {
SsaInsn defInsn = ssaMeth.getDefinitionForRegister(reg);
+
if (defInsn instanceof NormalSsaInsn) {
NormalSsaInsn ndefInsn = (NormalSsaInsn) defInsn;
@@ -127,19 +127,18 @@
* interference graph in the process. The insn currently must be the
* last insn in a block.
*
- * @param insn non-null; insn to insert move before, must be last insn
- * in block.
- * @param reg non-null; SSA register to duplicate
- * @return non-null; spec of new SSA register created by move
+ * @param insn {@code non-null;} insn to insert move before, must
+ * be last insn in block
+ * @param reg {@code non-null;} SSA register to duplicate
+ * @return {@code non-null;} spec of new SSA register created by move
*/
protected final RegisterSpec insertMoveBefore(SsaInsn insn,
RegisterSpec reg) {
-
SsaBasicBlock block = insn.getBlock();
ArrayList<SsaInsn> insns = block.getInsns();
int insnIndex = insns.indexOf(insn);
- if (insnIndex < 0 ) {
+ if (insnIndex < 0) {
throw new IllegalArgumentException (
"specified insn is not in this block");
}
@@ -155,19 +154,17 @@
}
/*
- * Get new register and make new move instruction
+ * Get new register and make new move instruction.
*/
- // new result must not have associated local variable
+ // The new result must not have an associated local variable.
RegisterSpec newRegSpec = RegisterSpec.make(ssaMeth.makeNewSsaReg(),
reg.getTypeBearer());
- SsaInsn toAdd;
-
- toAdd = SsaInsn.makeFromRop(
- new PlainInsn(Rops.opMove(newRegSpec.getType()),
- SourcePosition.NO_INFO, newRegSpec,
- RegisterSpecList.make(reg)), block);
+ SsaInsn toAdd = SsaInsn.makeFromRop(
+ new PlainInsn(Rops.opMove(newRegSpec.getType()),
+ SourcePosition.NO_INFO, newRegSpec,
+ RegisterSpecList.make(reg)), block);
insns.add(insnIndex, toAdd);
@@ -179,17 +176,13 @@
*/
IntSet liveOut = block.getLiveOutRegs();
-
- RegisterSpec result = insn.getResult();
- int resultReg = (result == null) ? -1 : result.getReg();
-
IntIterator liveOutIter = liveOut.iterator();
- while(liveOutIter.hasNext()) {
+ while (liveOutIter.hasNext()) {
interference.add(newReg, liveOutIter.next());
}
- // Everything that's a source in the last insn interferes
+ // Everything that's a source in the last insn interferes.
RegisterSpecList sources = insn.getSources();
int szSources = sources.size();
diff --git a/dx/src/com/android/dx/ssa/back/SsaToRop.java b/dx/src/com/android/dx/ssa/back/SsaToRop.java
index 1c59549..0ecbead 100644
--- a/dx/src/com/android/dx/ssa/back/SsaToRop.java
+++ b/dx/src/com/android/dx/ssa/back/SsaToRop.java
@@ -38,7 +38,9 @@
import com.android.dx.util.Hex;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.BitSet;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -46,55 +48,67 @@
* Converts a method in SSA form to ROP form.
*/
public class SsaToRop {
-
+ /** local debug flag */
private static final boolean DEBUG = false;
- /** non-null; method to process */
+ /** {@code non-null;} method to process */
private final SsaMethod ssaMeth;
/**
- * true if the converter should attempt to minimize
+ * {@code true} if the converter should attempt to minimize
* the rop-form register count
*/
private final boolean minimizeRegisters;
- /** interference graph */
- private InterferenceGraph interference;
+ /** {@code non-null;} interference graph */
+ private final InterferenceGraph interference;
/**
* Converts a method in SSA form to ROP form.
- * @param ssaMeth input
- * @return non-null; rop-form output
+ *
+ * @param ssaMeth {@code non-null;} method to process
+ * @param minimizeRegisters {@code true} if the converter should
+ * attempt to minimize the rop-form register count
+ * @return {@code non-null;} rop-form output
*/
public static RopMethod convertToRopMethod(SsaMethod ssaMeth,
boolean minimizeRegisters) {
return new SsaToRop(ssaMeth, minimizeRegisters).convert();
}
- private SsaToRop(final SsaMethod ssaMethod, boolean minimizeRegisters) {
+ /**
+ * 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
+ */
+ private SsaToRop(SsaMethod ssaMethod, boolean minimizeRegisters) {
this.minimizeRegisters = minimizeRegisters;
this.ssaMeth = ssaMethod;
+ this.interference =
+ LivenessAnalyzer.constructInterferenceGraph(ssaMethod);
}
+ /**
+ * Performs the conversion.
+ *
+ * @return {@code non-null;} rop-form output
+ */
private RopMethod convert() {
- interference = LivenessAnalyzer.constructInterferenceGraph(ssaMeth);
-
if (DEBUG) {
interference.dumpToStdout();
}
- RegisterAllocator allocator;
- RegisterMapper mapper;
+ // These are other allocators for debugging or historical comparison:
+ // allocator = new NullRegisterAllocator(ssaMeth, interference);
+ // allocator = new FirstFitAllocator(ssaMeth, interference);
- // These are other allocators for debugging or historical comparison
+ RegisterAllocator allocator =
+ new FirstFitLocalCombiningAllocator(ssaMeth, interference,
+ minimizeRegisters);
- //allocator = new NullRegisterAllocator(ssaMeth, interference);
- //allocator = new FirstFitAllocator(ssaMeth, interference);
-
- allocator = new FirstFitLocalCombiningAllocator(ssaMeth, interference,
- minimizeRegisters);
-
- mapper = allocator.allocateRegisters();
+ RegisterMapper mapper = allocator.allocateRegisters();
if (DEBUG) {
System.out.println("Printing reg map");
@@ -113,22 +127,20 @@
removeEmptyGotos();
- RopMethod ropMethod;
-
- ropMethod = convertToRop();
-
+ RopMethod ropMethod = new RopMethod(convertBasicBlocks(),
+ ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
ropMethod = new IdenticalBlockCombiner(ropMethod).process();
return ropMethod;
}
-
/**
- * 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 blocks containing the real return or
- * throw statements must be removed.
+ * 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
+ * blocks containing the real return or throw statements must be
+ * removed.
*/
private void removeEmptyGotos() {
final ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
@@ -139,8 +151,7 @@
if ((insns.size() == 1)
&& (insns.get(0).getOpcode() == Rops.GOTO)) {
-
- BitSet preds = (BitSet)b.getPredecessors().clone();
+ BitSet preds = (BitSet) b.getPredecessors().clone();
for (int i = preds.nextSetBit(0); i >= 0;
i = preds.nextSetBit(i + 1)) {
@@ -154,89 +165,49 @@
}
/**
- * 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.
- */
- public int[] getRegistersByFrequency() {
- int regCount = ssaMeth.getRegCount();
- Integer[] ret = new Integer[ssaMeth.getRegCount()];
-
- for (int i = 0; i < regCount; i++) {
- ret[i] = i;
- }
-
- java.util.Arrays.sort(ret, new java.util.Comparator<Integer>() {
- public int compare (Integer o1, Integer o2) {
- return ssaMeth.getUseListForRegister(o2).size()
- - ssaMeth.getUseListForRegister(o1).size();
- }
-
- public boolean equals(Object o) {
- return o == this;
- }
- });
-
- int result[] = new int[regCount];
-
- for (int i = 0; i < regCount; i++) {
- result[i] = ret[i];
- }
-
- return result;
- }
-
- /**
- * See Appel 19.6
- * To remove the phi instructions in an edge-split SSA representation
- * we know we can always insert a move in a predecessor block
+ * See Appel 19.6. To remove the phi instructions in an edge-split
+ * SSA representation we know we can always insert a move in a
+ * predecessor block.
*/
private void removePhiFunctions() {
- for (SsaBasicBlock block: ssaMeth.getBlocks()) {
- // Add moves in all the pred blocks for each phi insn`
- block.forEachPhiInsn(new PhiVisitor(block));
- // Delete the phi insns
+ 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));
+
+ // Delete the phi insns.
block.removeAllPhiInsns();
}
/*
- * After all move insns have been added: sort them so they don't
- * destructively interfere
+ * After all move insns have been added, sort them so they don't
+ * destructively interfere.
*/
- for (SsaBasicBlock block: ssaMeth.getBlocks()) {
+ for (SsaBasicBlock block : blocks) {
block.scheduleMovesFromPhis();
}
}
/**
- * PhiSuccessorUpdater for adding move instructions to predecessors based
- * on phi insns.
+ * Helper for {@link #removePhiFunctions}: PhiSuccessorUpdater for
+ * adding move instructions to predecessors based on phi insns.
*/
- private class PhiVisitor implements PhiInsn.Visitor {
- SsaBasicBlock block;
+ private static class PhiVisitor implements PhiInsn.Visitor {
+ private final ArrayList<SsaBasicBlock> blocks;
- PhiVisitor (final SsaBasicBlock block) {
- this.block = block;
+ public PhiVisitor(ArrayList<SsaBasicBlock> blocks) {
+ this.blocks = blocks;
}
- public void visitPhiInsn (PhiInsn insn) {
- RegisterSpecList sources;
- RegisterSpec result;
- ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
-
- sources = insn.getSources();
- result = insn.getResult();
-
+ public void visitPhiInsn(PhiInsn insn) {
+ RegisterSpecList sources = insn.getSources();
+ RegisterSpec result = insn.getResult();
int sz = sources.size();
- for (int i = 0; i <sz; i++) {
- RegisterSpec source;
-
- source = sources.get(i);
-
- SsaBasicBlock predBlock;
-
- predBlock = blocks.get(
+ for (int i = 0; i < sz; i++) {
+ RegisterSpec source = sources.get(i);
+ SsaBasicBlock predBlock = blocks.get(
insn.predBlockIndexForSourcesIndex(i));
predBlock.addMoveToEnd(result, source);
@@ -250,9 +221,7 @@
* Dalvik calling convention.
*/
private void moveParametersToHighRegisters() {
-
int paramWidth = ssaMeth.getParamWidth();
-
BasicRegisterMapper mapper
= new BasicRegisterMapper(ssaMeth.getRegCount());
int regCount = ssaMeth.getRegCount();
@@ -273,29 +242,25 @@
ssaMeth.mapRegisters(mapper);
}
- private RopMethod convertToRop() {
- return new RopMethod(convertBasicBlocks(),
- ssaMeth.blockIndexToRopLabel(ssaMeth.getEntryBlockIndex()));
- }
-
/**
* @return rop-form basic block list
*/
private BasicBlockList convertBasicBlocks() {
ArrayList<SsaBasicBlock> blocks = ssaMeth.getBlocks();
- // Exit block may be null
+
+ // Exit block may be null.
SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
int ropBlockCount = ssaMeth.getCountReachableBlocks();
- // Don't count the exit block, if it exists
+ // Don't count the exit block, if it exists.
ropBlockCount -= (exitBlock == null) ? 0 : 1;
BasicBlockList result = new BasicBlockList(ropBlockCount);
- // Convert all the reachable blocks except the exit block
+ // Convert all the reachable blocks except the exit block.
int ropBlockIndex = 0;
- for(SsaBasicBlock b : blocks) {
+ for (SsaBasicBlock b : blocks) {
if (b.isReachable() && b != exitBlock) {
result.set(ropBlockIndex++, convertBasicBlock(b));
}
@@ -303,8 +268,8 @@
// The exit block, which is discarded, must do nothing.
if (exitBlock != null && exitBlock.getInsns().size() != 0) {
- throw new RuntimeException
- ("Exit block must have no insns when leaving SSA form");
+ throw new RuntimeException(
+ "Exit block must have no insns when leaving SSA form");
}
return result;
@@ -314,11 +279,10 @@
* Validates that a basic block is a valid end predecessor. It must
* end in a RETURN or a THROW. Throws a runtime exception on error.
*
- * @param b non-null; block to validate
+ * @param b {@code non-null;} block to validate
* @throws RuntimeException on error
*/
private void verifyValidExitPredecessor(SsaBasicBlock b) {
-
ArrayList<SsaInsn> insns = b.getInsns();
SsaInsn lastInsn = insns.get(insns.size() - 1);
Rop opcode = lastInsn.getOpcode();
@@ -334,22 +298,21 @@
* Converts a single basic block to rop form.
*
* @param block SSA block to process
- * @return ROP block
+ * @return {@code non-null;} ROP block
*/
private BasicBlock convertBasicBlock(SsaBasicBlock block) {
- BasicBlock result;
IntList successorList = block.getRopLabelSuccessorList();
int primarySuccessorLabel = block.getPrimarySuccessorRopLabel();
- // Filter out any reference to the SSA form's exit block
- // exit block may be null
+ // Filter out any reference to the SSA form's exit block.
+
+ // Exit block may be null.
SsaBasicBlock exitBlock = ssaMeth.getExitBlock();
-
int exitRopLabel = (exitBlock == null) ? -1 : exitBlock.getRopLabel();
if (successorList.contains(exitRopLabel)) {
if (successorList.size() > 1) {
- throw new RuntimeException (
+ throw new RuntimeException(
"Exit predecessor must have no other successors"
+ Hex.u2(block.getRopLabel()));
} else {
@@ -362,7 +325,7 @@
successorList.setImmutable();
- result = new BasicBlock(
+ BasicBlock result = new BasicBlock(
block.getRopLabel(), convertInsns(block.getInsns()),
successorList,
primarySuccessorLabel);
@@ -371,16 +334,14 @@
}
/**
- * Converts an insn list to rop form
- * @param ssaInsns non-null;old instructions
- * @return non-null; immutable instruction list
+ * Converts an insn list to rop form.
+ *
+ * @param ssaInsns {@code non-null;} old instructions
+ * @return {@code non-null;} immutable instruction list
*/
private InsnList convertInsns(ArrayList<SsaInsn> ssaInsns) {
- InsnList result;
- int insnCount;
-
- insnCount = ssaInsns.size();
- result = new InsnList (insnCount);
+ int insnCount = ssaInsns.size();
+ InsnList result = new InsnList(insnCount);
for (int i = 0; i < insnCount; i++) {
result.set(i, ssaInsns.get(i).toRopInsn());
@@ -390,4 +351,35 @@
return result;
}
+
+ /**
+ * <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.
+ */
+ public int[] getRegistersByFrequency() {
+ int regCount = ssaMeth.getRegCount();
+ Integer[] ret = new Integer[regCount];
+
+ for (int i = 0; i < regCount; i++) {
+ ret[i] = i;
+ }
+
+ Arrays.sort(ret, new Comparator<Integer>() {
+ public int compare(Integer o1, Integer o2) {
+ return ssaMeth.getUseListForRegister(o2).size()
+ - ssaMeth.getUseListForRegister(o1).size();
+ }
+ });
+
+ int result[] = new int[regCount];
+
+ for (int i = 0; i < regCount; i++) {
+ result[i] = ret[i];
+ }
+
+ return result;
+ }
}
diff --git a/dx/src/com/android/dx/ssa/package-info.java b/dx/src/com/android/dx/ssa/package-info.java
index 45d9ad6..582a327 100644
--- a/dx/src/com/android/dx/ssa/package-info.java
+++ b/dx/src/com/android/dx/ssa/package-info.java
@@ -19,7 +19,7 @@
/**
* <h1>An introduction to SSA Form</h1>
*
- * This package contains classes associated with dx's <code>SSA</code>
+ * This package contains classes associated with dx's {@code SSA}
* intermediate form. This form is a static-single-assignment representation of
* Rop-form a method with Rop-form-like instructions (with the addition of a
* {@link PhiInsn phi instriction}. This form is intended to make it easy to
@@ -47,7 +47,7 @@
* <li> {@link PhiInsn} instances represent "phi" operators defined in SSA
* literature. They must be the first N instructions in a basic block.
* <li> {@link NormalSsaInsn} instances represent instructions that directly
- * correspond to <code>Rop</code> form.
+ * correspond to {@code Rop} form.
* </ul>
*
* <h3>Classes related to optimization steps</h3>
@@ -74,14 +74,14 @@
*
* <h3>Conversion into SSA Form</h3>
*
- * {@link SsaConverter#convertToSsaMethod} takes a <code>RopMethod</code> and
- * returns a fully-converted <code>SsaMethod</code>. The conversion process
+ * {@link SsaConverter#convertToSsaMethod} takes a {@code RopMethod} and
+ * returns a fully-converted {@code SsaMethod}. The conversion process
* is roughly as follows:
*
* <ol>
* <li> The Rop-form method, its blocks and their instructions are directly
- * wrapped in <code>SsaMethod</code>, <code>SsaBasicBlock</code> and
- * <code>SsaInsn</code> instances. Nothing else changes.
+ * wrapped in {@code SsaMethod}, {@code SsaBasicBlock} and
+ * {@code SsaInsn} instances. Nothing else changes.
* <li> Critical control-flow graph edges are {@link SsaConverter#edgeSplit
* split} and new basic blocks inserted as required to meet the constraints
* necessary for the ultimate SSA representation.
@@ -89,7 +89,7 @@
* Rop registers to local variables necessary during phi placement. This
* step could also be done in Rop form and then updated through the preceding
* steps.
- * <li> <code>Phi</code> instructions are {link SsaConverter#placePhiFunctions}
+ * <li> {@code Phi} instructions are {link SsaConverter#placePhiFunctions}
* placed in a semi-pruned fashion, which requires computation of {@link
* Dominators dominance graph} and each node's {@link DomFront
* dominance-frontier set}.
diff --git a/dx/src/com/android/dx/util/AnnotatedOutput.java b/dx/src/com/android/dx/util/AnnotatedOutput.java
index 0d95041..9b69a36 100644
--- a/dx/src/com/android/dx/util/AnnotatedOutput.java
+++ b/dx/src/com/android/dx/util/AnnotatedOutput.java
@@ -25,7 +25,7 @@
/**
* Get whether this instance will actually keep annotations.
*
- * @return <code>true</code> iff annotations are being kept
+ * @return {@code true} iff annotations are being kept
*/
public boolean annotates();
@@ -34,7 +34,7 @@
* Annotators may use the result of calling this method to inform their
* annotation activity.
*
- * @return <code>true</code> iff annotations are to be verbose
+ * @return {@code true} iff annotations are to be verbose
*/
public boolean isVerbose();
@@ -44,7 +44,7 @@
* annotation marks all subsequent output until another annotation
* call.
*
- * @param msg non-null; the annotation message
+ * @param msg {@code non-null;} the annotation message
*/
public void annotate(String msg);
@@ -55,9 +55,9 @@
* previous calls to this method, the new call "consumes" output
* after all the output covered by the previous calls.
*
- * @param amt >= 0; the amount of output for this annotation to
+ * @param amt {@code >= 0;} the amount of output for this annotation to
* cover
- * @param msg non-null; the annotation message
+ * @param msg {@code non-null;} the annotation message
*/
public void annotate(int amt, String msg);
@@ -73,7 +73,7 @@
* output, but annotaters are encouraged to attempt to avoid exceeding
* the indicated width.
*
- * @return >= 1; the maximum 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 c8588f8..db85571 100644
--- a/dx/src/com/android/dx/util/BitIntSet.java
+++ b/dx/src/com/android/dx/util/BitIntSet.java
@@ -44,7 +44,7 @@
/**
* Ensures that the bit set has the capacity to represent the given value.
*
- * @param value >= 0 value to represent
+ * @param value {@code >= 0;} value to represent
*/
private void ensureCapacity(int value) {
if (value >= Bits.getMax(bits)) {
@@ -118,12 +118,6 @@
return ret;
}
-
- /** @inheritDoc */
- public void remove() {
- BitIntSet.this.remove(idx);
- idx = Bits.findFirst(bits, idx+1);
- }
};
}
diff --git a/dx/src/com/android/dx/util/Bits.java b/dx/src/com/android/dx/util/Bits.java
index 0bc124c..1f45bd3 100644
--- a/dx/src/com/android/dx/util/Bits.java
+++ b/dx/src/com/android/dx/util/Bits.java
@@ -17,7 +17,7 @@
package com.android.dx.util;
/**
- * Utilities for treating <code>int[]</code>s as bit sets.
+ * Utilities for treating {@code int[]}s as bit sets.
*/
public final class Bits {
/**
@@ -30,8 +30,8 @@
/**
* Constructs a bit set to contain bits up to the given index (exclusive).
*
- * @param max >= 0; the maximum bit index (exclusive)
- * @return non-null; an appropriately-constructed instance
+ * @param max {@code >= 0;} the maximum bit index (exclusive)
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public static int[] makeBitSet(int max) {
int size = (max + 0x1f) >> 5;
@@ -41,8 +41,8 @@
/**
* Gets the maximum index (exclusive) for the given bit set.
*
- * @param bits non-null; bit set in question
- * @return >= 0; the maximum index (exclusive) that may be set
+ * @param bits {@code non-null;} bit set in question
+ * @return {@code >= 0;} the maximum index (exclusive) that may be set
*/
public static int getMax(int[] bits) {
return bits.length * 0x20;
@@ -51,8 +51,8 @@
/**
* Gets the value of the bit at the given index.
*
- * @param bits non-null; bit set to operate on
- * @param idx >= 0, < getMax(set); which bit
+ * @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
*/
public static boolean get(int[] bits, int idx) {
@@ -64,8 +64,8 @@
/**
* Sets the given bit to the given value.
*
- * @param bits non-null; bit set to operate on
- * @param idx >= 0, < getMax(set); which bit
+ * @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
*/
public static void set(int[] bits, int idx, boolean value) {
@@ -80,10 +80,10 @@
}
/**
- * Sets the given bit to <code>true</code>.
+ * Sets the given bit to {@code true}.
*
- * @param bits non-null; bit set to operate on
- * @param idx >= 0, < getMax(set); which bit
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0, < getMax(set);} which bit
*/
public static void set(int[] bits, int idx) {
int arrayIdx = idx >> 5;
@@ -92,10 +92,10 @@
}
/**
- * Sets the given bit to <code>false</code>.
+ * Sets the given bit to {@code false}.
*
- * @param bits non-null; bit set to operate on
- * @param idx >= 0, < getMax(set); which bit
+ * @param bits {@code non-null;} bit set to operate on
+ * @param idx {@code >= 0, < getMax(set);} which bit
*/
public static void clear(int[] bits, int idx) {
int arrayIdx = idx >> 5;
@@ -105,10 +105,10 @@
/**
* Returns whether or not the given bit set is empty, that is, whether
- * no bit is set to <code>true</code>.
+ * no bit is set to {@code true}.
*
- * @param bits non-null; bit set to operate on
- * @return <code>true</code> iff all bits are <code>false</code>
+ * @param bits {@code non-null;} bit set to operate on
+ * @return {@code true} iff all bits are {@code false}
*/
public static boolean isEmpty(int[] bits) {
int len = bits.length;
@@ -123,10 +123,10 @@
}
/**
- * Gets the number of bits set to <code>true</code> in the given bit set.
+ * Gets the number of bits set to {@code true} in the given bit set.
*
- * @param bits non-null; bit set to operate on
- * @return >= 0; the bit count (aka population count) of the set
+ * @param bits {@code non-null;} bit set to operate on
+ * @return {@code >= 0;} the bit count (aka population count) of the set
*/
public static int bitCount(int[] bits) {
int len = bits.length;
@@ -140,13 +140,13 @@
}
/**
- * Returns whether any bits are set to <code>true</code> in the
+ * Returns whether any bits are set to {@code true} in the
* specified range.
*
- * @param bits non-null; bit set to operate on
- * @param start >= 0; index of the first bit in the range (inclusive)
- * @param end >= 0; index of the last bit in the range (exclusive)
- * @return <code>true</code> if any bit is set to <code>true</code> in
+ * @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)
+ * @return {@code true} if any bit is set to {@code true} in
* the indicated range
*/
public static boolean anyInRange(int[] bits, int start, int end) {
@@ -158,10 +158,10 @@
* Finds the lowest-order bit set at or after the given index in the
* given bit set.
*
- * @param bits non-null; bit set to operate on
- * @param idx >= 0; minimum index to return
- * @return >= -1; lowest-order bit set at or after <code>idx</code>,
- * or <code>-1</code> if there is no appropriate bit index to return
+ * @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},
+ * or {@code -1} if there is no appropriate bit index to return
*/
public static int findFirst(int[] bits, int idx) {
int len = bits.length;
@@ -183,12 +183,12 @@
/**
* Finds the lowest-order bit set at or after the given index in the
- * given <code>int</code>.
+ * given {@code int}.
*
* @param value the value in question
* @param idx 0..31 the minimum bit index to return
- * @return >= -1; lowest-order bit set at or after <code>idx</code>,
- * or <code>-1</code> if there is no appropriate bit index to return
+ * @return {@code >= -1;} lowest-order bit set at or after {@code idx},
+ * or {@code -1} if there is no appropriate bit index to return
*/
public static int findFirst(int value, int idx) {
value &= ~((1 << idx) - 1); // Mask off too-low bits.
@@ -197,13 +197,13 @@
}
/**
- * Ors bit array <code>b</code> into bit array <code>a</code>.
- * <code>a.length</code> must be greater than or equal to
- * <code>b.length</code>.
+ * Ors bit array {@code b} into bit array {@code a}.
+ * {@code a.length} must be greater than or equal to
+ * {@code b.length}.
*
- * @param a non-null; int array to be ored with other argument. This
+ * @param a {@code non-null;} int array to be ored with other argument. This
* argument is modified.
- * @param b non-null; int array to be ored into <code>a</code>. This
+ * @param b {@code non-null;} int array to be ored into {@code a}. This
* argument is not modified.
*/
public static void or(int[] a, int[] b) {
diff --git a/dx/src/com/android/dx/util/ByteArray.java b/dx/src/com/android/dx/util/ByteArray.java
index 3fcf293..6bd6e5f 100644
--- a/dx/src/com/android/dx/util/ByteArray.java
+++ b/dx/src/com/android/dx/util/ByteArray.java
@@ -21,28 +21,28 @@
import java.io.InputStream;
/**
- * Wrapper for a <code>byte[]</code>, which provides read-only access and
+ * Wrapper for a {@code byte[]}, which provides read-only access and
* can "reveal" a partial slice of the underlying array.
*
* <b>Note:</b> Multibyte accessors all use big-endian order.
*/
public final class ByteArray {
- /** non-null; underlying array */
+ /** {@code non-null;} underlying array */
private final byte[] bytes;
- /** <code>>= 0</code>; start index of the slice (inclusive) */
+ /** {@code >= 0}; start index of the slice (inclusive) */
private final int start;
- /** <code>>= 0, <= bytes.length</code>; size computed as
- * <code>end - start</code> (in the constructor) */
+ /** {@code >= 0, <= bytes.length}; size computed as
+ * {@code end - start} (in the constructor) */
private final int size;
/**
* Constructs an instance.
*
- * @param bytes non-null; the underlying array
- * @param start <code>>= 0</code>; start index of the slice (inclusive)
- * @param end <code>>= start, <= bytes.length</code>; end index of
+ * @param bytes {@code non-null;} the underlying array
+ * @param start {@code >= 0;} start index of the slice (inclusive)
+ * @param end {@code >= start, <= bytes.length;} end index of
* the slice (exclusive)
*/
public ByteArray(byte[] bytes, int start, int end) {
@@ -68,9 +68,9 @@
}
/**
- * Constructs an instance from an entire <code>byte[]</code>.
+ * Constructs an instance from an entire {@code byte[]}.
*
- * @param bytes non-null; the underlying array
+ * @param bytes {@code non-null;} the underlying array
*/
public ByteArray(byte[] bytes) {
this(bytes, 0, bytes.length);
@@ -79,7 +79,7 @@
/**
* Gets the size of the array, in bytes.
*
- * @return >= 0; the size
+ * @return {@code >= 0;} the size
*/
public int size() {
return size;
@@ -88,10 +88,10 @@
/**
* Returns a slice (that is, a sub-array) of this instance.
*
- * @param start <code>>= 0</code>; start index of the slice (inclusive)
- * @param end <code>>= start, <= size()</code>; end index of
+ * @param start {@code >= 0;} start index of the slice (inclusive)
+ * @param end {@code >= start, <= size();} end index of
* the slice (exclusive)
- * @return non-null; the slice
+ * @return {@code non-null;} the slice
*/
public ByteArray slice(int start, int end) {
checkOffsets(start, end);
@@ -103,9 +103,9 @@
* offset into this instance.
*
* @param offset offset into this instance
- * @param bytes non-null; (alleged) underlying array
- * @return corresponding offset into <code>bytes</code>
- * @throws IllegalArgumentException thrown if <code>bytes</code> is
+ * @param bytes {@code non-null;} (alleged) underlying array
+ * @return corresponding offset into {@code bytes}
+ * @throws IllegalArgumentException thrown if {@code bytes} is
* not the underlying array of this instance
*/
public int underlyingOffset(int offset, byte[] bytes) {
@@ -117,10 +117,10 @@
}
/**
- * Gets the <code>signed byte</code> value at a particular offset.
+ * Gets the {@code signed byte} value at a particular offset.
*
- * @param off <code>>= 0, < size(); offset to fetch
- * @return <code>signed byte</code> at that offset
+ * @param off {@code >= 0, < size();} offset to fetch
+ * @return {@code signed byte} at that offset
*/
public int getByte(int off) {
checkOffsets(off, off + 1);
@@ -128,10 +128,10 @@
}
/**
- * Gets the <code>signed short</code> value at a particular offset.
+ * Gets the {@code signed short} value at a particular offset.
*
- * @param off <code>>= 0, < (size() - 1); offset to fetch
- * @return <code>signed short</code> at that offset
+ * @param off {@code >= 0, < (size() - 1);} offset to fetch
+ * @return {@code signed short} at that offset
*/
public int getShort(int off) {
checkOffsets(off, off + 2);
@@ -139,10 +139,10 @@
}
/**
- * Gets the <code>signed int</code> value at a particular offset.
+ * Gets the {@code signed int} value at a particular offset.
*
- * @param off <code>>= 0, < (size() - 3); offset to fetch
- * @return <code>signed int</code> at that offset
+ * @param off {@code >= 0, < (size() - 3);} offset to fetch
+ * @return {@code signed int} at that offset
*/
public int getInt(int off) {
checkOffsets(off, off + 4);
@@ -153,10 +153,10 @@
}
/**
- * Gets the <code>signed long</code> value at a particular offset.
+ * Gets the {@code signed long} value at a particular offset.
*
- * @param off <code>>= 0, < (size() - 7); offset to fetch
- * @return <code>signed int</code> at that offset
+ * @param off {@code >= 0, < (size() - 7);} offset to fetch
+ * @return {@code signed int} at that offset
*/
public long getLong(int off) {
checkOffsets(off, off + 8);
@@ -173,10 +173,10 @@
}
/**
- * Gets the <code>unsigned byte</code> value at a particular offset.
+ * Gets the {@code unsigned byte} value at a particular offset.
*
- * @param off <code>>= 0, < size(); offset to fetch
- * @return <code>unsigned byte</code> at that offset
+ * @param off {@code >= 0, < size();} offset to fetch
+ * @return {@code unsigned byte} at that offset
*/
public int getUnsignedByte(int off) {
checkOffsets(off, off + 1);
@@ -184,10 +184,10 @@
}
/**
- * Gets the <code>unsigned short</code> value at a particular offset.
+ * Gets the {@code unsigned short} value at a particular offset.
*
- * @param off <code>>= 0, < (size() - 1); offset to fetch
- * @return <code>unsigned short</code> at that offset
+ * @param off {@code >= 0, < (size() - 1);} offset to fetch
+ * @return {@code unsigned short} at that offset
*/
public int getUnsignedShort(int off) {
checkOffsets(off, off + 2);
@@ -196,11 +196,11 @@
/**
* Copies the contents of this instance into the given raw
- * <code>byte[]</code> at the given offset. The given array must be
+ * {@code byte[]} at the given offset. The given array must be
* large enough.
*
- * @param out non-null; array to hold the output
- * @param offset non-null; index into <code>out</code> for the first
+ * @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
*/
public void getBytes(byte[] out, int offset) {
@@ -226,7 +226,7 @@
}
/**
- * Gets the <code>signed byte</code> value at the given offset,
+ * Gets the {@code signed byte} value at the given offset,
* without doing any argument checking.
*
* @param off offset to fetch
@@ -237,7 +237,7 @@
}
/**
- * Gets the <code>unsigned byte</code> value at the given offset,
+ * Gets the {@code unsigned byte} value at the given offset,
* without doing any argument checking.
*
* @param off offset to fetch
@@ -248,26 +248,26 @@
}
/**
- * Gets a <code>DataInputStream</code> that reads from this instance,
+ * Gets a {@code DataInputStream} that reads from this instance,
* 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 non-null; an appropriately-constructed
- * <code>DataInputStream</code> instance
+ * @return {@code non-null;} an appropriately-constructed
+ * {@code DataInputStream} instance
*/
public MyDataInputStream makeDataInputStream() {
return new MyDataInputStream(makeInputStream());
}
/**
- * Gets a <code>InputStream</code> that reads from this instance,
+ * Gets a {@code InputStream} that reads from this instance,
* 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 non-null; an appropriately-constructed
- * <code>InputStream</code> instancex
+ * @return {@code non-null;} an appropriately-constructed
+ * {@code InputStream} instancex
*/
public MyInputStream makeInputStream() {
return new MyInputStream();
@@ -280,7 +280,7 @@
/**
* Gets the current cursor.
*
- * @return 0..size(); the cursor
+ * @return {@code 0..size();} the cursor
*/
public int getCursor();
}
@@ -345,7 +345,7 @@
/**
* Gets the current cursor.
*
- * @return 0..size(); the cursor
+ * @return {@code 0..size();} the cursor
*/
public int getCursor() {
return cursor;
@@ -357,8 +357,8 @@
* simply so that the cursor of a wrapped {@link #MyInputStream}
* instance may be easily determined.
*/
- public class MyDataInputStream extends DataInputStream {
- /** non-null; the underlying {@link #MyInputStream} */
+ public static class MyDataInputStream extends DataInputStream {
+ /** {@code non-null;} the underlying {@link #MyInputStream} */
private final MyInputStream wrapped;
public MyDataInputStream(MyInputStream wrapped) {
@@ -370,7 +370,7 @@
/**
* Gets the current cursor.
*
- * @return 0..size(); the cursor
+ * @return {@code 0..size();} the cursor
*/
public int getCursor() {
return wrapped.getCursor();
diff --git a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
index 457a603..5fcf5d8 100644
--- a/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
+++ b/dx/src/com/android/dx/util/ByteArrayAnnotatedOutput.java
@@ -22,7 +22,7 @@
/**
* Implementation of {@link AnnotatedOutput} which stores the written data
- * into a <code>byte[]</code>.
+ * into a {@code byte[]}.
*
* <p><b>Note:</b> As per the {@link Output} interface, multi-byte
* writes all use little-endian order.</p>
@@ -38,26 +38,26 @@
*/
private final boolean stretchy;
- /** non-null; the data itself */
+ /** {@code non-null;} the data itself */
private byte[] data;
- /** >= 0; current output cursor */
+ /** {@code >= 0;} current output cursor */
private int cursor;
/** whether annotations are to be verbose */
private boolean verbose;
/**
- * null-ok; list of annotations, or <code>null</code> if this instance
+ * {@code null-ok;} list of annotations, or {@code null} if this instance
* isn't keeping them
*/
private ArrayList<Annotation> annotations;
- /** >= 40 (if used); the desired maximum annotation width */
+ /** {@code >= 40 (if used);} the desired maximum annotation width */
private int annotationWidth;
/**
- * >= 8 (if used); the number of bytes of hex output to use
+ * {@code >= 8 (if used);} the number of bytes of hex output to use
* in annotations
*/
private int hexCols;
@@ -69,7 +69,7 @@
* capacity of the resulting instance. Also, the constructed
* instance does not keep annotations by default.
*
- * @param data non-null; data array to use for output
+ * @param data {@code non-null;} data array to use for output
*/
public ByteArrayAnnotatedOutput(byte[] data) {
this(data, false);
@@ -87,7 +87,7 @@
/**
* Internal constructor.
*
- * @param data non-null; data array to use for output
+ * @param data {@code non-null;} data array to use for output
* @param stretchy whether the instance is to be stretchy
*/
private ByteArrayAnnotatedOutput(byte[] data, boolean stretchy) {
@@ -105,25 +105,25 @@
}
/**
- * Gets the underlying <code>byte[]</code> of this instance, which
+ * Gets the underlying {@code byte[]} of this instance, which
* may be larger than the number of bytes written
*
* @see #toByteArray
*
- * @return non-null; the <code>byte[]</code>
+ * @return {@code non-null;} the {@code byte[]}
*/
public byte[] getArray() {
return data;
}
/**
- * Constructs and returns a new <code>byte[]</code> that contains
+ * 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 non-null; an appropriately-constructed array
+ * @return {@code non-null;} an appropriately-constructed array
*/
public byte[] toByteArray() {
byte[] result = new byte[cursor];
@@ -419,7 +419,7 @@
* be called only once per instance, and only before any data has been
* written to the it.
*
- * @param annotationWidth >= 40; the desired maximum annotation width
+ * @param annotationWidth {@code >= 40;} the desired maximum annotation width
* @param verbose whether or not to indicate verbose annotations
*/
public void enableAnnotations(int annotationWidth, boolean verbose) {
@@ -474,7 +474,7 @@
/**
* Writes the annotated content of this instance to the given writer.
*
- * @param out non-null; where to write to
+ * @param out {@code non-null;} where to write to
*/
public void writeAnnotationsTo(Writer out) throws IOException {
int width2 = getAnnotationWidth();
@@ -538,7 +538,7 @@
* Reallocates the underlying array if necessary. Calls to this method
* should be guarded by a test of {@link #stretchy}.
*
- * @param desiredSize >= 0; the desired minimum total size of the array
+ * @param desiredSize {@code >= 0;} the desired minimum total size of the array
*/
private void ensureCapacity(int desiredSize) {
if (data.length < desiredSize) {
@@ -552,25 +552,25 @@
* Annotation on output.
*/
private static class Annotation {
- /** >= 0; start of annotated range (inclusive) */
+ /** {@code >= 0;} start of annotated range (inclusive) */
private final int start;
/**
- * >= 0; end of annotated range (exclusive);
- * <code>Integer.MAX_VALUE</code> if unclosed
+ * {@code >= 0;} end of annotated range (exclusive);
+ * {@code Integer.MAX_VALUE} if unclosed
*/
private int end;
- /** non-null; annotation text */
+ /** {@code non-null;} annotation text */
private final String text;
/**
* Constructs an instance.
*
- * @param start >= 0; start of annotated range
- * @param end >= start; end of annotated range (exclusive) or
- * <code>Integer.MAX_VALUE</code> if unclosed
- * @param text non-null; annotation text
+ * @param start {@code >= 0;} start of annotated range
+ * @param end {@code >= start;} end of annotated range (exclusive) or
+ * {@code Integer.MAX_VALUE} if unclosed
+ * @param text {@code non-null;} annotation text
*/
public Annotation(int start, int end, String text) {
this.start = start;
@@ -581,8 +581,8 @@
/**
* Constructs an instance. It is initally unclosed.
*
- * @param start >= 0; start of annotated range
- * @param text non-null; annotation text
+ * @param start {@code >= 0;} start of annotated range
+ * @param text {@code non-null;} annotation text
*/
public Annotation(int start, String text) {
this(start, Integer.MAX_VALUE, text);
@@ -592,7 +592,7 @@
* Sets the end as given, but only if the instance is unclosed;
* otherwise, do nothing.
*
- * @param end >= start; the end
+ * @param end {@code >= start;} the end
*/
public void setEndIfUnset(int end) {
if (this.end == Integer.MAX_VALUE) {
@@ -603,7 +603,7 @@
/**
* Sets the end as given.
*
- * @param end >= start; the end
+ * @param end {@code >= start;} the end
*/
public void setEnd(int end) {
this.end = end;
@@ -630,7 +630,7 @@
/**
* Gets the text.
*
- * @return non-null; the text
+ * @return {@code non-null;} the text
*/
public String getText() {
return text;
diff --git a/dx/src/com/android/dx/util/ExceptionWithContext.java b/dx/src/com/android/dx/util/ExceptionWithContext.java
index 035546e..7f8523c 100644
--- a/dx/src/com/android/dx/util/ExceptionWithContext.java
+++ b/dx/src/com/android/dx/util/ExceptionWithContext.java
@@ -24,7 +24,7 @@
*/
public class ExceptionWithContext
extends RuntimeException {
- /** non-null; human-oriented context of the exception */
+ /** {@code non-null;} human-oriented context of the exception */
private StringBuffer context;
/**
@@ -33,9 +33,9 @@
* {@link ExceptionWithContext}, or a newly-constructed exception if it
* was not.
*
- * @param ex non-null; the exception to augment
- * @param str non-null; context to add
- * @return non-null; an appropriate instance
+ * @param ex {@code non-null;} the exception to augment
+ * @param str {@code non-null;} context to add
+ * @return {@code non-null;} an appropriate instance
*/
public static ExceptionWithContext withContext(Throwable ex, String str) {
ExceptionWithContext ewc;
@@ -62,7 +62,7 @@
/**
* Constructs an instance.
*
- * @param cause null-ok; exception that caused this one
+ * @param cause {@code null-ok;} exception that caused this one
*/
public ExceptionWithContext(Throwable cause) {
this(null, cause);
@@ -72,7 +72,7 @@
* Constructs an instance.
*
* @param message human-oriented message
- * @param cause null-ok; exception that caused this one
+ * @param cause {@code null-ok;} exception that caused this one
*/
public ExceptionWithContext(String message, Throwable cause) {
super((message != null) ? message :
@@ -105,7 +105,7 @@
/**
* Adds a line of context to this instance.
*
- * @param str non-null; new context
+ * @param str {@code non-null;} new context
*/
public void addContext(String str) {
if (str == null) {
@@ -121,7 +121,7 @@
/**
* Gets the context.
*
- * @return non-null; the context
+ * @return {@code non-null;} the context
*/
public String getContext() {
return context.toString();
@@ -130,7 +130,7 @@
/**
* Prints the message and context.
*
- * @param out non-null; where to print to
+ * @param out {@code non-null;} where to print to
*/
public void printContext(PrintStream out) {
out.println(getMessage());
@@ -140,7 +140,7 @@
/**
* Prints the message and context.
*
- * @param out non-null; where to print to
+ * @param out {@code non-null;} where to print to
*/
public void printContext(PrintWriter out) {
out.println(getMessage());
diff --git a/dx/src/com/android/dx/util/FileUtils.java b/dx/src/com/android/dx/util/FileUtils.java
index 07a7c7e..3f51207 100644
--- a/dx/src/com/android/dx/util/FileUtils.java
+++ b/dx/src/com/android/dx/util/FileUtils.java
@@ -35,8 +35,8 @@
* Reads the named file, translating {@link IOException} to a
* {@link RuntimeException} of some sort.
*
- * @param fileName non-null; name of the file to read
- * @return non-null; contents of the file
+ * @param fileName {@code non-null;} name of the file to read
+ * @return {@code non-null;} contents of the file
*/
public static byte[] readFile(String fileName) {
File file = new File(fileName);
@@ -47,8 +47,8 @@
* Reads the given file, translating {@link IOException} to a
* {@link RuntimeException} of some sort.
*
- * @param file non-null; the file to read
- * @return non-null; contents of the file
+ * @param file {@code non-null;} the file to read
+ * @return {@code non-null;} contents of the file
*/
public static byte[] readFile(File file) {
if (!file.exists()) {
diff --git a/dx/src/com/android/dx/util/FixedSizeList.java b/dx/src/com/android/dx/util/FixedSizeList.java
index 7b7d325..17d773c 100644
--- a/dx/src/com/android/dx/util/FixedSizeList.java
+++ b/dx/src/com/android/dx/util/FixedSizeList.java
@@ -23,11 +23,11 @@
*/
public class FixedSizeList
extends MutabilityControl implements ToHuman {
- /** non-null; array of elements */
+ /** {@code non-null;} array of elements */
private Object[] arr;
/**
- * Constructs an instance. All indices initially contain <code>null</code>.
+ * Constructs an instance. All indices initially contain {@code null}.
*
* @param size the size of the list
*/
@@ -94,10 +94,10 @@
/**
* Gets a customized string form for this instance.
*
- * @param prefix null-ok; prefix for the start of the result
- * @param separator null-ok; separator to insert between each item
- * @param suffix null-ok; suffix for the end of the result
- * @return non-null; the custom string
+ * @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
+ * @return {@code non-null;} the custom string
*/
public String toString(String prefix, String separator, String suffix) {
return toString0(prefix, separator, suffix, false);
@@ -108,10 +108,10 @@
* only work if every element of the list implements {@link
* ToHuman}.
*
- * @param prefix null-ok; prefix for the start of the result
- * @param separator null-ok; separator to insert between each item
- * @param suffix null-ok; suffix for the end of the result
- * @return non-null; the custom string
+ * @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
+ * @return {@code non-null;} the custom string
*/
public String toHuman(String prefix, String separator, String suffix) {
return toString0(prefix, separator, suffix, true);
@@ -126,7 +126,7 @@
/**
* Shrinks this instance to fit, by removing any unset
- * (<code>null</code>) elements, leaving the remaining elements in
+ * ({@code null}) elements, leaving the remaining elements in
* their original order.
*/
public void shrinkToFit() {
@@ -165,12 +165,12 @@
/**
* 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</code>. This method is
+ * will throw {@code NullPointerException}. This method is
* protected so that subclasses may offer a safe type-checked
* public interface to their clients.
*
- * @param n >= 0, < size(); which element
- * @return non-null; the indicated element
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code non-null;} the indicated element
*/
protected final Object get0(int n) {
try {
@@ -188,13 +188,13 @@
}
/**
- * Gets the indicated element, allowing <code>null</code>s to be
+ * Gets the indicated element, allowing {@code null}s to be
* returned. This method is protected so that subclasses may
* (optionally) offer a safe type-checked public interface to
* their clients.
*
- * @param n >= 0, < size(); which element
- * @return null-ok; the indicated element
+ * @param n {@code >= 0, < size();} which element
+ * @return {@code null-ok;} the indicated element
*/
protected final Object getOrNull0(int n) {
return arr[n];
@@ -206,8 +206,8 @@
* subclasses may offer a safe type-checked public interface to
* their clients.
*
- * @param n >= 0, < size(); which element
- * @param obj null-ok; the value to store
+ * @param n {@code >= 0, < size();} which element
+ * @param obj {@code null-ok;} the value to store
*/
protected final void set0(int n, Object obj) {
throwIfImmutable();
@@ -239,11 +239,11 @@
* Helper for {@link #toString} and {@link #toHuman}, which both of
* those call to pretty much do everything.
*
- * @param prefix null-ok; prefix for the start of the result
- * @param separator null-ok; separator to insert between each item
- * @param suffix null-ok; suffix for the end of the result
+ * @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
- * @return non-null; the custom string
+ * @return {@code non-null;} the custom string
*/
private String toString0(String prefix, String separator, String suffix,
boolean human) {
diff --git a/dx/src/com/android/dx/util/Hex.java b/dx/src/com/android/dx/util/Hex.java
index cf4c130..cb71e5e 100644
--- a/dx/src/com/android/dx/util/Hex.java
+++ b/dx/src/com/android/dx/util/Hex.java
@@ -28,10 +28,10 @@
}
/**
- * Formats a <code>long</code> as an 8-byte unsigned hex value.
+ * Formats a {@code long} as an 8-byte unsigned hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String u8(long v) {
char[] result = new char[16];
@@ -44,10 +44,10 @@
}
/**
- * Formats an <code>int</code> as a 4-byte unsigned hex value.
+ * Formats an {@code int} as a 4-byte unsigned hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String u4(int v) {
char[] result = new char[8];
@@ -60,10 +60,10 @@
}
/**
- * Formats an <code>int</code> as a 3-byte unsigned hex value.
+ * Formats an {@code int} as a 3-byte unsigned hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String u3(int v) {
char[] result = new char[6];
@@ -76,10 +76,10 @@
}
/**
- * Formats an <code>int</code> as a 2-byte unsigned hex value.
+ * Formats an {@code int} as a 2-byte unsigned hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String u2(int v) {
char[] result = new char[4];
@@ -92,12 +92,12 @@
}
/**
- * Formats an <code>int</code> as either a 2-byte unsigned hex value
+ * 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 non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String u2or4(int v) {
if (v == (char) v) {
@@ -108,10 +108,10 @@
}
/**
- * Formats an <code>int</code> as a 1-byte unsigned hex value.
+ * Formats an {@code int} as a 1-byte unsigned hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String u1(int v) {
char[] result = new char[2];
@@ -124,10 +124,10 @@
}
/**
- * Formats an <code>int</code> as a 4-bit unsigned hex nibble.
+ * Formats an {@code int} as a 4-bit unsigned hex nibble.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String uNibble(int v) {
char[] result = new char[1];
@@ -137,10 +137,10 @@
}
/**
- * Formats a <code>long</code> as an 8-byte signed hex value.
+ * Formats a {@code long} as an 8-byte signed hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String s8(long v) {
char[] result = new char[17];
@@ -161,10 +161,10 @@
}
/**
- * Formats an <code>int</code> as a 4-byte signed hex value.
+ * Formats an {@code int} as a 4-byte signed hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String s4(int v) {
char[] result = new char[9];
@@ -185,10 +185,10 @@
}
/**
- * Formats an <code>int</code> as a 2-byte signed hex value.
+ * Formats an {@code int} as a 2-byte signed hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String s2(int v) {
char[] result = new char[5];
@@ -209,10 +209,10 @@
}
/**
- * Formats an <code>int</code> as a 1-byte signed hex value.
+ * Formats an {@code int} as a 1-byte signed hex value.
*
* @param v value to format
- * @return non-null; formatted form
+ * @return {@code non-null;} formatted form
*/
public static String s1(int v) {
char[] result = new char[3];
@@ -233,18 +233,18 @@
}
/**
- * Formats a hex dump of a portion of a <code>byte[]</code>. The result
+ * 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>""</code>).
+ * in which case the result is always the empty string ({@code ""}).
*
- * @param arr non-null; array to format
- * @param offset >= 0; offset to the part to dump
- * @param length >= 0; number of bytes to dump
- * @param outOffset >= 0; first output offset to print
- * @param bpl >= 0; number of bytes of output per line
- * @param addressLength {2,4,6,8}; number of characters for each address
+ * @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
+ * @param outOffset {@code >= 0;} first output offset to print
+ * @param bpl {@code >= 0;} number of bytes of output per line
+ * @param addressLength {@code {2,4,6,8};} number of characters for each address
* header
- * @return non-null; a string of the dump
+ * @return {@code non-null;} a string of the dump
*/
public static String dump(byte[] arr, int offset, int length,
int outOffset, int bpl, int addressLength) {
diff --git a/dx/src/com/android/dx/util/HexParser.java b/dx/src/com/android/dx/util/HexParser.java
index 4b6b7b2..3d0c992 100644
--- a/dx/src/com/android/dx/util/HexParser.java
+++ b/dx/src/com/android/dx/util/HexParser.java
@@ -28,7 +28,7 @@
}
/**
- * Parses the given text as hex, returning a <code>byte[]</code>
+ * Parses the given text as hex, returning a {@code byte[]}
* corresponding to the text. The format is simple: Each line may
* start with a hex offset followed by a colon (which is verified
* and presumably used just as a comment), and then consists of
@@ -38,8 +38,8 @@
* of the subsequent characters is used, until the next double
* quote. Quoted strings may not span multiple lines.
*
- * @param src non-null; the source string
- * @return non-null; the parsed form
+ * @param src {@code non-null;} the source string
+ * @return {@code non-null;} the parsed form
*/
public static byte[] parse(String src) {
int len = src.length();
diff --git a/dx/src/com/android/dx/util/IndentingWriter.java b/dx/src/com/android/dx/util/IndentingWriter.java
index db4e0a2..92f0b55 100644
--- a/dx/src/com/android/dx/util/IndentingWriter.java
+++ b/dx/src/com/android/dx/util/IndentingWriter.java
@@ -27,31 +27,31 @@
* line.
*/
public final class IndentingWriter extends FilterWriter {
- /** null-ok; optional prefix for every line */
+ /** {@code null-ok;} optional prefix for every line */
private final String prefix;
- /** > 0; the maximum output width */
+ /** {@code > 0;} the maximum output width */
private final int width;
- /** > 0; the maximum indent */
+ /** {@code > 0;} the maximum indent */
private final int maxIndent;
- /** >= 0; current output column (zero-based) */
+ /** {@code >= 0;} current output column (zero-based) */
private int column;
/** whether indent spaces are currently being collected */
private boolean collectingIndent;
- /** >= 0; current indent amount */
+ /** {@code >= 0;} current indent amount */
private int indent;
/**
* Constructs an instance.
*
- * @param out non-null; writer to send final output to
- * @param width >= 0; the maximum output width (not including
- * <code>prefix</code>), or <code>0</code> for no maximum
- * @param prefix non-null; the prefix for each line
+ * @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
+ * @param prefix {@code non-null;} the prefix for each line
*/
public IndentingWriter(Writer out, int width, String prefix) {
super(out);
@@ -78,9 +78,9 @@
/**
* Constructs a no-prefix instance.
*
- * @param out non-null; writer to send final output to
- * @param width >= 0; the maximum output width (not including
- * <code>prefix</code>), or <code>0</code> for no maximum
+ * @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
*/
public IndentingWriter(Writer out, int width) {
this(out, width, "");
diff --git a/dx/src/com/android/dx/util/IntIterator.java b/dx/src/com/android/dx/util/IntIterator.java
index 88181b5..4caa439 100644
--- a/dx/src/com/android/dx/util/IntIterator.java
+++ b/dx/src/com/android/dx/util/IntIterator.java
@@ -35,10 +35,4 @@
* @throws java.util.NoSuchElementException if no next element exists
*/
int next();
-
- /**
- * Removes a value from the collection underlying this iterator.
- * May throw UnsupportedOperationException().
- */
-// void remove();
}
diff --git a/dx/src/com/android/dx/util/IntList.java b/dx/src/com/android/dx/util/IntList.java
index f60bbb5..c51c028 100644
--- a/dx/src/com/android/dx/util/IntList.java
+++ b/dx/src/com/android/dx/util/IntList.java
@@ -19,16 +19,16 @@
import java.util.Arrays;
/**
- * Simple list of <code>int</code>s.
+ * Simple list of {@code int}s.
*/
public final class IntList extends MutabilityControl {
- /** non-null; immutable, no-element instance */
+ /** {@code non-null;} immutable, no-element instance */
public static final IntList EMPTY = new IntList(0);
- /** non-null; array of elements */
+ /** {@code non-null;} array of elements */
private int[] values;
- /** >= 0; current size of the list */
+ /** {@code >= 0;} current size of the list */
private int size;
/** whether the values are currently sorted */
@@ -78,7 +78,7 @@
/**
* Constructs an empty instance.
*
- * @param initialCapacity >= 0; initial capacity of the list
+ * @param initialCapacity {@code >= 0;} initial capacity of the list
*/
public IntList(int initialCapacity) {
super(true);
@@ -165,7 +165,7 @@
/**
* Gets the indicated value.
*
- * @param n >= 0, < size(); which element
+ * @param n {@code >= 0, < size();} which element
* @return the indicated element's value
*/
public int get(int n) {
@@ -184,7 +184,7 @@
/**
* Sets the value at the given index.
*
- * @param n >= 0, < size(); which element
+ * @param n {@code >= 0, < size();} which element
* @param value value to store
*/
public void set(int n, int value) {
@@ -229,7 +229,7 @@
* current size (that is, insertion as a last element is legal but
* no further).
*
- * @param n >=0 <=size(); index of where to insert
+ * @param n {@code >= 0, <=size();} index of where to insert
* @param value value to insert
*/
public void insert(int n, int value) {
@@ -252,7 +252,7 @@
* Removes an element at a given index, shifting elements at greater
* indicies down one.
*
- * @param n >=0 < size(); index of element to remove
+ * @param n {@code >=0, < size();} index of element to remove
*/
public void removeIndex(int n) {
if (n >= size) {
@@ -307,7 +307,7 @@
/**
* Pops N elements off the end of the list and decreasing the size by N.
*
- * @param n >= 0; number of elements to remove from end.
+ * @param n {@code >= 0;} number of elements to remove from end.
* @exception IndexOutOfBoundsException if stack is smaller than N
*/
public void pop(int n) {
@@ -319,7 +319,7 @@
/**
* Shrinks the size of the list.
*
- * @param newSize >= 0; the new size
+ * @param newSize {@code >= 0;} the new size
*/
public void shrink(int newSize) {
if (newSize < 0) {
@@ -338,7 +338,7 @@
/**
* Makes and returns a mutable copy of the list.
*
- * @return non-null; an appropriately-constructed instance
+ * @return {@code non-null;} an appropriately-constructed instance
*/
public IntList mutableCopy() {
int sz = size;
@@ -380,12 +380,12 @@
/**
* Performs a binary search on a sorted list, returning the index of
* the given value if it is present or
- * <code>(-(insertion point) - 1)</code> if the value is not present.
+ * {@code (-(insertion point) - 1)} if the value is not present.
* If the list is not sorted, then reverts to linear search and returns
- * <code>-size()</code> if the element is not found.
+ * {@code -size()} if the element is not found.
*
* @param value value to find
- * @return index of value or <code>(-(insertion point) - 1)</code> if the
+ * @return index of value or {@code (-(insertion point) - 1)} if the
* value is not present
*/
public int binarysearch(int value) {
diff --git a/dx/src/com/android/dx/util/IntSet.java b/dx/src/com/android/dx/util/IntSet.java
index 10b6ee0..33b6bdd 100644
--- a/dx/src/com/android/dx/util/IntSet.java
+++ b/dx/src/com/android/dx/util/IntSet.java
@@ -44,24 +44,24 @@
boolean has(int value);
/**
- * Merges <code>other</code> into this set, so this set becomes the
+ * Merges {@code other} into this set, so this set becomes the
* union of the two.
*
- * @param other non-null; other set to merge with.
+ * @param other {@code non-null;} other set to merge with.
*/
void merge(IntSet other);
/**
* Returns the count of unique elements in this set.
*
- * @return > = 0; count of unique elements
+ * @return {@code > = 0;} count of unique elements
*/
int elements();
/**
* Iterates the set
*
- * @return non-null; a set iterator
+ * @return {@code non-null;} a set iterator
*/
IntIterator iterator();
}
diff --git a/dx/src/com/android/dx/util/LabeledItem.java b/dx/src/com/android/dx/util/LabeledItem.java
index cc6a0d2..b4856cf 100644
--- a/dx/src/com/android/dx/util/LabeledItem.java
+++ b/dx/src/com/android/dx/util/LabeledItem.java
@@ -24,7 +24,7 @@
/*
* Gets the label of this block.
*
- * @return >= 0; the label
+ * @return {@code >= 0;} the label
*/
public int getLabel();
}
diff --git a/dx/src/com/android/dx/util/LabeledList.java b/dx/src/com/android/dx/util/LabeledList.java
index 3168a38..28a148b 100644
--- a/dx/src/com/android/dx/util/LabeledList.java
+++ b/dx/src/com/android/dx/util/LabeledList.java
@@ -58,7 +58,7 @@
/**
* Gets the maximum label (exclusive) of any block added to this instance.
*
- * @return >= 0; the maximum label
+ * @return {@code >= 0;} the maximum label
*/
public int getMaxLabel() {
int sz = labelToIndex.size();
@@ -102,8 +102,8 @@
* Gets the index of the first item in the list with the given
* label, if any.
*
- * @param label >= 0; the label to look for
- * @return >= -1; the index of the so-labelled item, or <code>-1</code>
+ * @param label {@code >= 0;} the label to look for
+ * @return {@code >= -1;} the index of the so-labelled item, or {@code -1}
* if none is found
*/
public int indexOfLabel(int label) {
@@ -142,8 +142,8 @@
/**
* Sets the element at the given index.
*
- * @param n >= 0, < size(); which element
- * @param item null-ok; the value to store
+ * @param n {@code >= 0, < size();} which element
+ * @param item {@code null-ok;} the value to store
*/
protected void set(int n, LabeledItem item) {
LabeledItem old = (LabeledItem) getOrNull0(n);
diff --git a/dx/src/com/android/dx/util/Leb128Utils.java b/dx/src/com/android/dx/util/Leb128Utils.java
index dfd416f..6ed3a61 100644
--- a/dx/src/com/android/dx/util/Leb128Utils.java
+++ b/dx/src/com/android/dx/util/Leb128Utils.java
@@ -41,7 +41,6 @@
int count = 0;
while (remaining != 0) {
- value = remaining;
remaining >>= 7;
count++;
}
diff --git a/dx/src/com/android/dx/util/ListIntSet.java b/dx/src/com/android/dx/util/ListIntSet.java
index a9f79af..6d28a18 100644
--- a/dx/src/com/android/dx/util/ListIntSet.java
+++ b/dx/src/com/android/dx/util/ListIntSet.java
@@ -122,11 +122,6 @@
return ints.get(idx++);
}
-
- /** @inheritDoc */
- public void remove() {
- throw new UnsupportedOperationException();
- }
};
}
diff --git a/dx/src/com/android/dx/util/MutabilityControl.java b/dx/src/com/android/dx/util/MutabilityControl.java
index 8b3383b..14e0f2e 100644
--- a/dx/src/com/android/dx/util/MutabilityControl.java
+++ b/dx/src/com/android/dx/util/MutabilityControl.java
@@ -36,7 +36,7 @@
/**
* Constructs an instance, explicitly indicating the mutability.
*
- * @param mutable <code>true</code> iff this instance is mutable
+ * @param mutable {@code true} iff this instance is mutable
*/
public MutabilityControl(boolean mutable) {
this.mutable = mutable;
@@ -51,9 +51,9 @@
/**
* Checks to see whether or not this instance is immutable. This is the
- * same as calling <code>!isMutable()</code>.
+ * same as calling {@code !isMutable()}.
*
- * @return <code>true</code> iff this instance is immutable
+ * @return {@code true} iff this instance is immutable
*/
public final boolean isImmutable() {
return !mutable;
@@ -62,7 +62,7 @@
/**
* Checks to see whether or not this instance is mutable.
*
- * @return <code>true</code> iff this instance is mutable
+ * @return {@code true} iff this instance is mutable
*/
public final boolean isMutable() {
return mutable;
diff --git a/dx/src/com/android/dx/util/Output.java b/dx/src/com/android/dx/util/Output.java
index b3c3747..5e737ae 100644
--- a/dx/src/com/android/dx/util/Output.java
+++ b/dx/src/com/android/dx/util/Output.java
@@ -18,7 +18,7 @@
/**
* Interface for a sink for binary output. This is similar to
- * <code>java.util.DataOutput</code>, but no <code>IOExceptions</code>
+ * {@code java.util.DataOutput}, but no {@code IOExceptions}
* are declared, and multibyte output is defined to be little-endian.
*/
public interface Output {
@@ -26,7 +26,7 @@
* Gets the current cursor position. This is the same as the number of
* bytes written to this instance.
*
- * @return >= 0; the cursor position
+ * @return {@code >= 0;} the cursor position
*/
public int getCursor();
@@ -34,34 +34,34 @@
* Asserts that the cursor is the given value.
*
* @param expectedCursor the expected cursor value
- * @throws RuntimeException thrown if <code>getCursor() !=
- * expectedCursor</code>
+ * @throws RuntimeException thrown if {@code getCursor() !=
+ * expectedCursor}
*/
public void assertCursor(int expectedCursor);
/**
- * Writes a <code>byte</code> to this instance.
+ * 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</code> to this instance.
+ * 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</code> to this instance.
+ * Writes an {@code int} to this instance.
*
* @param value the value to write
*/
public void writeInt(int value);
/**
- * Writes a <code>long</code> to this instance.
+ * Writes a {@code long} to this instance.
*
* @param value the value to write
*/
@@ -73,7 +73,7 @@
* 7.6.
*
* @param value value to write, treated as an unsigned value
- * @return 1..5; the number of bytes actually written
+ * @return {@code 1..5;} the number of bytes actually written
*/
public int writeUnsignedLeb128(int value);
@@ -83,47 +83,47 @@
* 7.6.
*
* @param value value to write
- * @return 1..5; the number of bytes actually written
+ * @return {@code 1..5;} the number of bytes actually written
*/
public int writeSignedLeb128(int value);
/**
* Writes a {@link ByteArray} to this instance.
*
- * @param bytes non-null; the array to write
+ * @param bytes {@code non-null;} the array to write
*/
public void write(ByteArray bytes);
/**
- * Writes a portion of a <code>byte[]</code> to this instance.
+ * Writes a portion of a {@code byte[]} to this instance.
*
- * @param bytes non-null; the array to write
- * @param offset >= 0; offset into <code>bytes</code> for the first
+ * @param bytes {@code non-null;} the array to write
+ * @param offset {@code >= 0;} offset into {@code bytes} for the first
* byte to write
- * @param length >= 0; number of bytes to write
+ * @param length {@code >= 0;} number of bytes to write
*/
public void write(byte[] bytes, int offset, int length);
/**
- * Writes a <code>byte[]</code> to this instance. This is just
- * a convenient shorthand for <code>write(bytes, 0, bytes.length)</code>.
+ * Writes a {@code byte[]} to this instance. This is just
+ * a convenient shorthand for {@code write(bytes, 0, bytes.length)}.
*
- * @param bytes non-null; the array to write
+ * @param bytes {@code non-null;} the array to write
*/
public void write(byte[] bytes);
/**
- * Writes the given number of <code>0</code> bytes.
+ * Writes the given number of {@code 0} bytes.
*
- * @param count >= 0; the number of zeroes to write
+ * @param count {@code >= 0;} the number of zeroes to write
*/
public void writeZeroes(int count);
/**
- * Adds extra bytes if necessary (with value <code>0</code>) to
+ * Adds extra bytes if necessary (with value {@code 0}) to
* force alignment of the output cursor as given.
*
- * @param alignment > 0; the alignment; must be a power of two
+ * @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/ToHuman.java b/dx/src/com/android/dx/util/ToHuman.java
index 89bf4f7..b3a31a5 100644
--- a/dx/src/com/android/dx/util/ToHuman.java
+++ b/dx/src/com/android/dx/util/ToHuman.java
@@ -23,9 +23,9 @@
public interface ToHuman {
/**
* Return the "human" string form of this instance. This is
- * generally less "debuggy" than <code>toString()</code>.
+ * generally less "debuggy" than {@code toString()}.
*
- * @return non-null; the human string form
+ * @return {@code non-null;} the human string form
*/
public String toHuman();
}
diff --git a/dx/src/com/android/dx/util/TwoColumnOutput.java b/dx/src/com/android/dx/util/TwoColumnOutput.java
index cc9f7d4..a155c15 100644
--- a/dx/src/com/android/dx/util/TwoColumnOutput.java
+++ b/dx/src/com/android/dx/util/TwoColumnOutput.java
@@ -28,34 +28,34 @@
* one which goes on the right.
*/
public final class TwoColumnOutput {
- /** non-null; underlying writer for final output */
+ /** {@code non-null;} underlying writer for final output */
private final Writer out;
- /** > 0; the left column width */
+ /** {@code > 0;} the left column width */
private final int leftWidth;
- /** non-null; pending left column output */
+ /** {@code non-null;} pending left column output */
private final StringBuffer leftBuf;
- /** non-null; pending right column output */
+ /** {@code non-null;} pending right column output */
private final StringBuffer rightBuf;
- /** non-null; left column writer */
+ /** {@code non-null;} left column writer */
private final IndentingWriter leftColumn;
- /** non-null; right column writer */
+ /** {@code non-null;} right column writer */
private final IndentingWriter rightColumn;
/**
* Turns the given two strings (with widths) and spacer into a formatted
* two-column string.
*
- * @param s1 non-null; first string
- * @param width1 > 0; width of the first column
- * @param spacer non-null; spacer string
- * @param s2 non-null; second string
- * @param width2 > 0; width of the second column
- * @return non-null; an appropriately-formatted string
+ * @param s1 {@code non-null;} first string
+ * @param width1 {@code > 0;} width of the first column
+ * @param spacer {@code non-null;} spacer string
+ * @param s2 {@code non-null;} second string
+ * @param width2 {@code > 0;} width of the second column
+ * @return {@code non-null;} an appropriately-formatted string
*/
public static String toString(String s1, int width1, String spacer,
String s2, int width2) {
@@ -80,10 +80,10 @@
/**
* Constructs an instance.
*
- * @param out non-null; writer to send final output to
- * @param leftWidth > 0; width of the left column, in characters
- * @param rightWidth > 0; width of the right column, in characters
- * @param spacer non-null; spacer string to sit between the two columns
+ * @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
+ * @param spacer {@code non-null;} spacer string to sit between the two columns
*/
public TwoColumnOutput(Writer out, int leftWidth, int rightWidth,
String spacer) {
@@ -118,10 +118,10 @@
/**
* Constructs an instance.
*
- * @param out non-null; stream to send final output to
- * @param leftWidth >= 1; width of the left column, in characters
- * @param rightWidth >= 1; width of the right column, in characters
- * @param spacer non-null; spacer string to sit between the two columns
+ * @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
+ * @param spacer {@code non-null;} spacer string to sit between the two columns
*/
public TwoColumnOutput(OutputStream out, int leftWidth, int rightWidth,
String spacer) {
@@ -131,7 +131,7 @@
/**
* Gets the writer to use to write to the left column.
*
- * @return non-null; the left column writer
+ * @return {@code non-null;} the left column writer
*/
public Writer getLeft() {
return leftColumn;
@@ -140,7 +140,7 @@
/**
* Gets the writer to use to write to the right column.
*
- * @return non-null; the right column writer
+ * @return {@code non-null;} the right column writer
*/
public Writer getRight() {
return rightColumn;
@@ -226,8 +226,8 @@
* 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 non-null; the buffer in question
- * @param out non-null; the writer to use
+ * @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)
@@ -242,8 +242,8 @@
/**
* Writes the given number of spaces to the given writer.
*
- * @param out non-null; where to write
- * @param amt >= 0; the number of spaces to write
+ * @param out {@code non-null;} where to write
+ * @param amt {@code >= 0;} the number of spaces to write
*/
private static void writeSpaces(Writer out, int amt) throws IOException {
while (amt > 0) {
diff --git a/dx/src/com/android/dx/util/Writers.java b/dx/src/com/android/dx/util/Writers.java
index f10e400..632b082 100644
--- a/dx/src/com/android/dx/util/Writers.java
+++ b/dx/src/com/android/dx/util/Writers.java
@@ -20,7 +20,7 @@
import java.io.Writer;
/**
- * Utilities for dealing with <code>Writer</code>s.
+ * Utilities for dealing with {@code Writer}s.
*/
public final class Writers {
/**
@@ -31,12 +31,12 @@
}
/**
- * Makes a <code>PrintWriter</code> for the given <code>Writer</code>,
+ * Makes a {@code PrintWriter} for the given {@code Writer},
* returning the given writer if it already happens to be the right
* class.
*
- * @param writer non-null; writer to (possibly) wrap
- * @return non-null; an appropriate instance
+ * @param writer {@code non-null;} writer to (possibly) wrap
+ * @return {@code non-null;} an appropriate instance
*/
public static PrintWriter printWriterFor(Writer writer) {
if (writer instanceof PrintWriter) {
diff --git a/dx/src/com/android/dx/util/_tests/_Bits.java b/dx/src/com/android/dx/util/_tests/_Bits.java
index e529b50..a95fc14 100644
--- a/dx/src/com/android/dx/util/_tests/_Bits.java
+++ b/dx/src/com/android/dx/util/_tests/_Bits.java
@@ -21,7 +21,7 @@
import junit.framework.TestCase;
/**
- * Test the class <code>com.android.dx.util.Bits</code>.
+ * Test the class {@code com.android.dx.util.Bits}.
*/
public class _Bits
extends TestCase {
diff --git a/dx/src/com/android/dx/util/_tests/_IntList.java b/dx/src/com/android/dx/util/_tests/_IntList.java
index 241e8be..dadbd54 100644
--- a/dx/src/com/android/dx/util/_tests/_IntList.java
+++ b/dx/src/com/android/dx/util/_tests/_IntList.java
@@ -21,7 +21,7 @@
import junit.framework.TestCase;
/**
- * Test the class <code>com.android.dx.util.IntList</code>.
+ * Test the class {@code com.android.dx.util.IntList}.
*/
public class _IntList
extends TestCase {
diff --git a/dx/tests/111-use-null-as-array/Blort.java b/dx/tests/111-use-null-as-array/Blort.java
new file mode 100644
index 0000000..c16684f
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/Blort.java
@@ -0,0 +1,108 @@
+/*
+ * 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.
+ */
+
+public class Blort {
+ public static boolean test_getBooleanArray() {
+ boolean[] arr = null;
+ return arr[1];
+ }
+
+ public static byte test_getByteArray() {
+ byte[] arr = null;
+ return arr[2];
+ }
+
+ public static char test_getCharArray() {
+ char[] arr = null;
+ return arr[3];
+ }
+
+ public static double test_getDoubleArray() {
+ double[] arr = null;
+ return arr[4];
+ }
+
+ public static float test_getFloatArray() {
+ float[] arr = null;
+ return arr[5];
+ }
+
+ public static int test_getIntArray() {
+ int[] arr = null;
+ return arr[6];
+ }
+
+ public static long test_getLongArray() {
+ long[] arr = null;
+ return arr[7];
+ }
+
+ public static Object test_getObjectArray() {
+ Object[] arr = null;
+ return arr[8];
+ }
+
+ public static short test_getShortArray() {
+ short[] arr = null;
+ return arr[9];
+ }
+
+ public static void test_setBooleanArray() {
+ boolean[] arr = null;
+ arr[1] = true;
+ }
+
+ public static void test_setByteArray() {
+ byte[] arr = null;
+ arr[2] = (byte) 3;
+ }
+
+ public static void test_setCharArray() {
+ char[] arr = null;
+ arr[4] = (char) 5;
+ }
+
+ public static void test_setDoubleArray() {
+ double[] arr = null;
+ arr[6] = 7.0F;
+ }
+
+ public static void test_setFloatArray() {
+ float[] arr = null;
+ arr[8] = 9.0F;
+ }
+
+ public static void test_setIntArray() {
+ int[] arr = null;
+ arr[10] = 11;
+ }
+
+ public static void test_setLongArray() {
+ long[] arr = null;
+ arr[12] = 13;
+ }
+
+ public static void test_setObjectArray() {
+ Object[] arr = null;
+ arr[14] = "blort";
+ }
+
+ public static void test_setShortArray() {
+ short[] arr = null;
+ arr[15] = (short) 16;
+ }
+}
+
diff --git a/dx/tests/111-use-null-as-array/expected.txt b/dx/tests/111-use-null-as-array/expected.txt
new file mode 100644
index 0000000..7e2116b
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/expected.txt
@@ -0,0 +1,116 @@
+Blort.test_getBooleanArray:()Z:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 1 // #1
+ 0002: aget-byte v0, v0, v1
+ 0004: return v0
+Blort.test_getByteArray:()B:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 2 // #2
+ 0002: aget-byte v0, v0, v1
+ 0004: return v0
+Blort.test_getCharArray:()C:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 3 // #3
+ 0002: aget-char v0, v0, v1
+ 0004: return v0
+Blort.test_getDoubleArray:()D:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 4 // #4
+ 0002: aget-wide v0, v0, v1
+ 0004: return-wide v0
+Blort.test_getFloatArray:()F:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 5 // #5
+ 0002: aget v0, v0, v1
+ 0004: return v0
+Blort.test_getIntArray:()I:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 6 // #6
+ 0002: aget v0, v0, v1
+ 0004: return v0
+Blort.test_getLongArray:()J:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 7 // #7
+ 0002: aget-wide v0, v0, v1
+ 0004: return-wide v0
+Blort.test_getObjectArray:()Ljava/lang/Object;:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 8 // #0008
+ 0003: aget-object v0, v0, v1
+ 0005: return-object v0
+Blort.test_getShortArray:()S:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 9 // #0009
+ 0003: aget-short v0, v0, v1
+ 0005: return v0
+Blort.test_setBooleanArray:()V:
+regs: 0002; ins: 0000; outs: 0000
+ 0000: const/4 v1, #int 1 // #1
+ 0001: const/4 v0, #null // #0
+ 0002: aput v1, v0, v1
+ 0004: return-void
+Blort.test_setByteArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 2 // #2
+ 0002: const/4 v2, #int 3 // #3
+ 0003: aput v2, v0, v1
+ 0005: return-void
+Blort.test_setCharArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 4 // #4
+ 0002: const/4 v2, #int 5 // #5
+ 0003: aput v2, v0, v1
+ 0005: return-void
+Blort.test_setDoubleArray:()V:
+regs: 0004; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/4 v1, #int 6 // #6
+ 0002: const-wide/high16 v2, #double 7.0 // #401c000000000000
+ 0004: aput-wide v2, v0, v1
+ 0006: return-void
+Blort.test_setFloatArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 8 // #0008
+ 0003: const/high16 v2, #float 9.0 // #41100000
+ 0005: aput v2, v0, v1
+ 0007: return-void
+Blort.test_setIntArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 10 // #000a
+ 0003: const/16 v2, #int 11 // #000b
+ 0005: aput v2, v0, v1
+ 0007: return-void
+Blort.test_setLongArray:()V:
+regs: 0004; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 12 // #000c
+ 0003: const-wide/16 v2, #long 13 // #000d
+ 0005: aput-wide v2, v0, v1
+ 0007: return-void
+Blort.test_setObjectArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 14 // #000e
+ 0003: const-string v2, "blort"
+ 0005: aput-object v2, v0, v1
+ 0007: return-void
+Blort.test_setShortArray:()V:
+regs: 0003; ins: 0000; outs: 0000
+ 0000: const/4 v0, #null // #0
+ 0001: const/16 v1, #int 15 // #000f
+ 0003: const/16 v2, #int 16 // #0010
+ 0005: aput v2, v0, v1
+ 0007: return-void
diff --git a/dx/tests/111-use-null-as-array/info.txt b/dx/tests/111-use-null-as-array/info.txt
new file mode 100644
index 0000000..624386d
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/info.txt
@@ -0,0 +1,18 @@
+This is a smoke test of dex conversion, which checks to see that uses
+of a known-null in contexts that require a specific type end up getting
+converted to the type in question. When executed, this sort of code
+will inevitably throw a NullPointerException, but if the opcode weren't
+correct, they would instead incorrectly fail verification.
+
+If you inspect the expected output of this test, you will see that
+there are some surprising instructions in there, such as using
+aget-byte for what was a boolean[] in the source code. In these cases,
+the resulting output is still correct (passes verification and will
+throw a NullPointerException if ever executed). However, it happens
+that during translation there simply wasn't enough information to
+recover the "true" original meaning at the level of actual opcode
+selection.
+
+This test compares emitted code against a known-good (via eyeballing)
+version, so it is possible for this test to spuriously fail if other
+aspects of conversion end up altering the output in innocuous ways.
diff --git a/dx/tests/111-use-null-as-array/run b/dx/tests/111-use-null-as-array/run
new file mode 100644
index 0000000..7e4e1e8
--- /dev/null
+++ b/dx/tests/111-use-null-as-array/run
@@ -0,0 +1,19 @@
+#!/bin/bash
+#
+# 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.
+
+$JAVAC -g -d . Blort.java
+dx --debug --dex --positions=none --no-locals \
+ --dump-to=- --dump-method="Blort.test*" *.class
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/Annotation.java b/libcore/annotation/src/main/java/java/lang/annotation/Annotation.java
index 43ad1bb..00707b1 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/Annotation.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/Annotation.java
@@ -22,17 +22,15 @@
* itself is <i>not</i> an annotation, and neither is an interface that simply
* extends this one. Only the compiler is able to create proper annotation
* types.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public interface Annotation {
/**
* Returns the type of this annotation.
- *
+ *
* @return A {@code Class} instance representing the annotation type.
- *
- * @since Android 1.0
*/
Class<? extends Annotation> annotationType();
@@ -70,14 +68,12 @@
* calling their {@code equals()} method.
* </li>
* </ul>
- *
+ *
* @param obj
* The object to compare to.
- *
- * @return {@code true} if {@code obj} is equal to this annotation,
- * {@code false} otherwise.
- *
- * @since Android 1.0
+ *
+ * @return {@code true} if {@code obj} is equal to this annotation,
+ * {@code false} otherwise.
*/
boolean equals(Object obj);
@@ -111,10 +107,8 @@
* calling their {@code hashCode} method.
* </li>
* </ul>
- *
+ *
* @return the hash code.
- *
- * @since Android 1.0
*/
int hashCode();
@@ -123,11 +117,9 @@
* strictly defined what the representation has to look like, but it usually
* consists of the name of the annotation, preceded by a "@". If the
* annotation contains field members, their names and values are also
- * included in the result.
+ * included in the result.
*
* @return the {@code String} that represents this annotation.
- *
- * @since Android 1.0
*/
String toString();
}
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java b/libcore/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java
index ce5c3a0..67775c7 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/AnnotationFormatError.java
@@ -22,8 +22,8 @@
* syntactically incorrect and the annotation parser is unable to process it.
* This exception is unlikely to ever occur, given that the code has been
* compiled by an ordinary Java compiler.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public class AnnotationFormatError extends Error {
@@ -31,11 +31,9 @@
/**
* Constructs an instance with the message provided.
- *
+ *
* @param message
* the details of the error.
- *
- * @since Android 1.0
*/
public AnnotationFormatError(String message) {
super(message);
@@ -43,14 +41,11 @@
/**
* Constructs an instance with a message and a cause.
- *
+ *
* @param message
* the details of the error.
- *
* @param cause
* the cause of the error or {@code null} if none.
- *
- * @since Android 1.0
*/
public AnnotationFormatError(String message, Throwable cause) {
super(message, cause);
@@ -60,11 +55,9 @@
* Constructs an instance with a cause. If the cause is not
* {@code null}, then {@code cause.toString()} is used as the
* error's message.
- *
+ *
* @param cause
* the cause of the error or {@code null} if none.
- *
- * @since Android 1.0
*/
public AnnotationFormatError(Throwable cause) {
super(cause == null ? null : cause.toString(), cause);
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java b/libcore/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java
index 5bb3cbf..0ff79ec 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/AnnotationTypeMismatchException.java
@@ -24,8 +24,8 @@
/**
* Indicates that an annotation type has changed since it was compiled or
* serialized.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public class AnnotationTypeMismatchException extends RuntimeException {
@@ -37,16 +37,13 @@
/**
* Constructs an instance for the given type element and the type found.
- *
+ *
* @param element
* the annotation type element.
- *
* @param foundType
* the invalid type that was found. This is actually the textual
* type description found in the binary class representation,
* so it may not be human-readable.
- *
- * @since Android 1.0
*/
public AnnotationTypeMismatchException(Method element, String foundType) {
super(Messages.getString("annotation.1", element, foundType)); //$NON-NLS-1$
@@ -56,10 +53,8 @@
/**
* Returns the method object for the invalid type.
- *
+ *
* @return a {@link Method} instance.
- *
- * @since Android 1.0
*/
public Method element() {
return element;
@@ -67,10 +62,8 @@
/**
* Returns the invalid type.
- *
+ *
* @return a string describing the invalid data.
- *
- * @since Android 1.0
*/
public String foundType() {
return foundType;
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/Documented.java b/libcore/annotation/src/main/java/java/lang/annotation/Documented.java
index 2849fd2..7e7f72f 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/Documented.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/Documented.java
@@ -20,8 +20,8 @@
/**
* Defines a meta-annotation for indicating that an annotation is documented and
* considered part of the public API.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/ElementType.java b/libcore/annotation/src/main/java/java/lang/annotation/ElementType.java
index 92f5109..f0f52aa 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/ElementType.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/ElementType.java
@@ -21,8 +21,8 @@
* Defines an enumeration for Java program elements. It is used in conjunction
* with the {@link Target} meta-annotation to restrict the use of an annotation
* to certain program elements.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public enum ElementType {
/**
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java b/libcore/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java
index 3a31551..a5d2068 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/IncompleteAnnotationException.java
@@ -23,8 +23,8 @@
* Indicates that an element of an annotation type was accessed that was added
* after the type was compiled or serialized. This does not apply to new
* elements that have default values.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public class IncompleteAnnotationException extends RuntimeException {
@@ -37,13 +37,11 @@
/**
* Constructs an instance with the incomplete annotation type and the name
* of the element that's missing.
- *
+ *
* @param annotationType
* the annotation type.
* @param elementName
* the name of the incomplete element.
- *
- * @since Android 1.0
*/
public IncompleteAnnotationException(
Class<? extends Annotation> annotationType, String elementName) {
@@ -54,10 +52,8 @@
/**
* Returns the annotation type.
- *
+ *
* @return a Class instance.
- *
- * @since Android 1.0
*/
public Class<? extends Annotation> annotationType() {
return annotationType;
@@ -65,10 +61,8 @@
/**
* Returns the incomplete element's name.
- *
+ *
* @return the name of the element.
- *
- * @since Android 1.0
*/
public String elementName() {
return elementName;
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/Inherited.java b/libcore/annotation/src/main/java/java/lang/annotation/Inherited.java
index cf16928..730d30a 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/Inherited.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/Inherited.java
@@ -20,8 +20,8 @@
/**
* Defines a meta-annotation for indicating that an annotation is automatically
* inherited.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/Retention.java b/libcore/annotation/src/main/java/java/lang/annotation/Retention.java
index 198fccc..275739e 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/Retention.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/Retention.java
@@ -21,15 +21,12 @@
* Defines a meta-annotation for determining the scope of retention for an
* annotation. If the retention annotation is not set {@code
* RetentionPolicy.CLASS} is used as default retention.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
- // BEGIN android-changed
- // copied from newer version of harmony
RetentionPolicy value();
- // END android-changed
}
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java b/libcore/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java
index 014b910..70de3b0 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/RetentionPolicy.java
@@ -21,8 +21,8 @@
* Defines an enumeration for annotation retention policies. Used in conjunction
* with the {@link Retention} annotation to specify an annotation's time-to-live
* in the overall development life cycle.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public enum RetentionPolicy {
/**
diff --git a/libcore/annotation/src/main/java/java/lang/annotation/Target.java b/libcore/annotation/src/main/java/java/lang/annotation/Target.java
index 1f53fa0..4ba0938 100644
--- a/libcore/annotation/src/main/java/java/lang/annotation/Target.java
+++ b/libcore/annotation/src/main/java/java/lang/annotation/Target.java
@@ -20,8 +20,8 @@
/**
* Defines a meta-annotation for determining what {@link ElementType}s an
* annotation can be applied to.
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
diff --git a/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java b/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java
index 1134887..5430286 100644
--- a/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java
+++ b/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/AnnotationTypeMismatchExceptionTest.java
@@ -65,7 +65,7 @@
Method m = methods[0];
AnnotationTypeMismatchException e = new AnnotationTypeMismatchException(
m, "some type");
- assertNotNull("can not instanciate AnnotationTypeMismatchException", e);
+ assertNotNull("can not instantiate AnnotationTypeMismatchException", e);
assertSame("wrong method name", m, e.element());
assertEquals("wrong found type", "some type", e.foundType());
}
diff --git a/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java b/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java
index de56330..5c718ed 100644
--- a/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java
+++ b/libcore/annotation/src/test/java/org/apache/harmony/annotation/tests/java/lang/annotation/IncompleteAnnotationExceptionTest.java
@@ -80,7 +80,7 @@
String elementName = "some element";
IncompleteAnnotationException e = new IncompleteAnnotationException(
clazz, elementName);
- assertNotNull("can not instanciate IncompleteAnnotationException", e);
+ assertNotNull("can not instantiate IncompleteAnnotationException", e);
assertSame("wrong annotation type", clazz, e.annotationType());
assertSame("wrong element name", elementName, e.elementName());
}
diff --git a/libcore/archive/src/main/java/java/util/jar/Attributes.java b/libcore/archive/src/main/java/java/util/jar/Attributes.java
index 5a4d923..4ee94df 100644
--- a/libcore/archive/src/main/java/java/util/jar/Attributes.java
+++ b/libcore/archive/src/main/java/java/util/jar/Attributes.java
@@ -17,6 +17,7 @@
package java.util.jar;
+import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -28,7 +29,6 @@
* The {@code Attributes} class is used to store values for manifest entries.
* Attribute keys are generally instances of {@code Attributes.Name}. Values
* associated with attribute keys are of type {@code String}.
- * @since Android 1.0
*/
public class Attributes implements Cloneable, Map<Object, Object> {
@@ -37,8 +37,6 @@
* {@link Attributes.Name}) of a JAR file manifest to arbitrary values. The
* attribute names thus are obtained from the {@link Manifest} for
* convenience.
- *
- * @since Android 1.0
*/
protected Map<Object, Object> map;
@@ -46,46 +44,35 @@
* The name part of the name/value pairs constituting an attribute as
* defined by the specification of the JAR manifest. May be composed of the
* following ASCII signs as defined in the EBNF below:
- *
+ *
* <pre>
* name = alphanum *headerchar
* headerchar = alphanum | - | _
- * alphanum = {A-Z} | {a-z} | {0-9}
+ * alphanum = {A-Z} | {a-z} | {0-9}
* </pre>
- *
- * @since Android 1.0
*/
public static class Name {
- private final String name;
+ private final byte[] name;
private int hashCode;
/**
* The class path (a main attribute).
- *
- * @since Android 1.0
*/
public static final Name CLASS_PATH = new Name("Class-Path"); //$NON-NLS-1$
/**
* The version of the manifest file (a main attribute).
- *
- * @since Android 1.0
*/
- public static final Name MANIFEST_VERSION = new Name(
- "Manifest-Version"); //$NON-NLS-1$
+ public static final Name MANIFEST_VERSION = new Name("Manifest-Version"); //$NON-NLS-1$
/**
* The main class's name (for stand-alone applications).
- *
- * @since Android 1.0
*/
public static final Name MAIN_CLASS = new Name("Main-Class"); //$NON-NLS-1$
/**
* Defines the signature version of the JAR file.
- *
- * @since Android 1.0
*/
public static final Name SIGNATURE_VERSION = new Name(
"Signature-Version"); //$NON-NLS-1$
@@ -98,16 +85,12 @@
/**
* The {@code Sealed} manifest attribute which may have the value
* {@code true} for sealed archives.
- *
- * @since Android 1.0
*/
public static final Name SEALED = new Name("Sealed"); //$NON-NLS-1$
/**
* The {@code Implementation-Title} attribute whose value is a string
* that defines the title of the extension implementation.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_TITLE = new Name(
"Implementation-Title"); //$NON-NLS-1$
@@ -115,8 +98,6 @@
/**
* The {@code Implementation-Version} attribute defining the version of
* the extension implementation.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_VERSION = new Name(
"Implementation-Version"); //$NON-NLS-1$
@@ -124,8 +105,6 @@
/**
* The {@code Implementation-Vendor} attribute defining the organization
* that maintains the extension implementation.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_VENDOR = new Name(
"Implementation-Vendor"); //$NON-NLS-1$
@@ -133,8 +112,6 @@
/**
* The {@code Specification-Title} attribute defining the title of the
* extension specification.
- *
- * @since Android 1.0
*/
public static final Name SPECIFICATION_TITLE = new Name(
"Specification-Title"); //$NON-NLS-1$
@@ -142,8 +119,6 @@
/**
* The {@code Specification-Version} attribute defining the version of
* the extension specification.
- *
- * @since Android 1.0
*/
public static final Name SPECIFICATION_VERSION = new Name(
"Specification-Version"); //$NON-NLS-1$
@@ -151,8 +126,6 @@
/**
* The {@code Specification-Vendor} attribute defining the organization
* that maintains the extension specification.
- *
- * @since Android 1.0
*/
public static final Name SPECIFICATION_VENDOR = new Name(
"Specification-Vendor"); //$NON-NLS-1$
@@ -160,23 +133,17 @@
/**
* The {@code Extension-List} attribute defining the extensions that are
* needed by the applet.
- *
- * @since Android 1.0
*/
public static final Name EXTENSION_LIST = new Name("Extension-List"); //$NON-NLS-1$
/**
* The {@code Extension-Name} attribute which defines the unique name of
* the extension.
- *
- * @since Android 1.0
*/
public static final Name EXTENSION_NAME = new Name("Extension-Name"); //$NON-NLS-1$
/**
* The {@code Extension-Installation} attribute.
- *
- * @since Android 1.0
*/
public static final Name EXTENSION_INSTALLATION = new Name(
"Extension-Installation"); //$NON-NLS-1$
@@ -185,8 +152,6 @@
* The {@code Implementation-Vendor-Id} attribute specifies the vendor
* of an extension implementation if the applet requires an
* implementation from a specific vendor.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_VENDOR_ID = new Name(
"Implementation-Vendor-Id"); //$NON-NLS-1$
@@ -195,91 +160,112 @@
* The {@code Implementation-URL} attribute specifying a URL that can be
* used to obtain the most recent version of the extension if the
* required version is not already installed.
- *
- * @since Android 1.0
*/
public static final Name IMPLEMENTATION_URL = new Name(
"Implementation-URL"); //$NON-NLS-1$
+ static final Name NAME = new Name("Name");
+
/**
* A String which must satisfy the following EBNF grammar to specify an
* additional attribute:
- *
+ *
* <pre>
* name = alphanum *headerchar
* headerchar = alphanum | - | _
* alphanum = {A-Z} | {a-z} | {0-9}
* </pre>
- *
+ *
* @param s
* The Attribute string.
* @exception IllegalArgumentException
* if the string does not satisfy the EBNF grammar.
- * @since Android 1.0
*/
public Name(String s) {
int i = s.length();
- if (i == 0 || i > 70) {
+ if (i == 0 || i > Manifest.LINE_LENGTH_LIMIT - 2) {
throw new IllegalArgumentException();
}
+
+ name = new byte[i];
+
for (; --i >= 0;) {
char ch = s.charAt(i);
if (!((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
|| ch == '_' || ch == '-' || (ch >= '0' && ch <= '9'))) {
throw new IllegalArgumentException(s);
}
+ name[i] = (byte) ch;
}
- name = s;
+ }
+
+ /**
+ * A private constructor for a trusted attribute name.
+ */
+ Name(byte[] buf) {
+ name = buf;
+ }
+
+ byte[] getBytes() {
+ return name;
}
/**
* Returns this attribute name.
- *
+ *
* @return the attribute name.
- * @since Android 1.0
*/
@Override
public String toString() {
- return name;
+ try {
+ return new String(name, "ISO-8859-1");
+ } catch (UnsupportedEncodingException iee) {
+ throw new InternalError(iee.getLocalizedMessage());
+ }
}
/**
* returns whether the argument provided is the same as the attribute
* name.
- *
+ *
* @return if the attribute names correspond.
- * @param an
+ * @param object
* An attribute name to be compared with this name.
- * @since Android 1.0
*/
@Override
- public boolean equals(Object an) {
- if (an == null) {
+ public boolean equals(Object object) {
+ if (object == null || object.getClass() != getClass()
+ || object.hashCode() != hashCode()) {
return false;
}
- return an.getClass() == this.getClass()
- && name.equalsIgnoreCase(((Name) an).name);
+
+ return Util.equalsIgnoreCase(name, ((Name) object).name);
}
/**
* Computes a hash code of the name.
- *
+ *
* @return the hash value computed from the name.
- * @since Android 1.0
*/
@Override
public int hashCode() {
if (hashCode == 0) {
- hashCode = Util.toASCIILowerCase("name").hashCode();
+ int hash = 0, multiplier = 1;
+ for (int i = name.length - 1; i >= 0; i--) {
+ // 'A' & 0xDF == 'a' & 0xDF, ..., 'Z' & 0xDF == 'z' & 0xDF
+ hash += (name[i] & 0xDF) * multiplier;
+ int shifted = multiplier << 5;
+ multiplier = shifted - multiplier;
+ }
+ hashCode = hash;
}
return hashCode;
}
+
}
/**
* Constructs an {@code Attributes} instance.
- *
- * @since Android 1.0
*/
public Attributes() {
map = new HashMap<Object, Object>();
@@ -288,23 +274,21 @@
/**
* Constructs an {@code Attributes} instance obtaining keys and values from
* the parameter {@code attrib}.
- *
+ *
* @param attrib
* The attributes to obtain entries from.
- * @since Android 1.0
*/
@SuppressWarnings("unchecked")
public Attributes(Attributes attrib) {
- map = (Map<Object, Object>)((HashMap) attrib.map).clone();
+ map = (Map<Object, Object>) ((HashMap) attrib.map).clone();
}
/**
* Constructs an {@code Attributes} instance with initial capacity of size
* {@code size}.
- *
+ *
* @param size
* Initial size of this {@code Attributes} instance.
- * @since Android 1.0
*/
public Attributes(int size) {
map = new HashMap<Object, Object>(size);
@@ -312,8 +296,6 @@
/**
* Removes all key/value pairs from this {@code Attributes}.
- *
- * @since Android 1.0
*/
public void clear() {
map.clear();
@@ -321,11 +303,10 @@
/**
* Determines whether this {@code Attributes} contains the specified key.
- *
+ *
* @param key
* The key to search for.
* @return {@code true} if the key is found, {@code false} otherwise.
- * @since Android 1.0
*/
public boolean containsKey(Object key) {
return map.containsKey(key);
@@ -333,11 +314,10 @@
/**
* Determines whether this {@code Attributes} contains the specified value.
- *
+ *
* @param value
* the value to search for.
* @return {@code true} if the value is found, {@code false} otherwise.
- * @since Android 1.0
*/
public boolean containsValue(Object value) {
return map.containsValue(value);
@@ -346,9 +326,8 @@
/**
* Returns a set containing map entries for each of the key/value pair
* contained in this {@code Attributes}.
- *
+ *
* @return a set of Map.Entry's
- * @since Android 1.0
*/
public Set<Map.Entry<Object, Object>> entrySet() {
return map.entrySet();
@@ -356,12 +335,11 @@
/**
* Returns the value associated with the parameter key.
- *
+ *
* @param key
* the key to search for.
* @return Object associated with key, or {@code null} if key does not
* exist.
- * @since Android 1.0
*/
public Object get(Object key) {
return map.get(key);
@@ -369,9 +347,8 @@
/**
* Determines whether this {@code Attributes} contains any keys.
- *
+ *
* @return {@code true} if one or more keys exist, {@code false} otherwise.
- * @since Android 1.0
*/
public boolean isEmpty() {
return map.isEmpty();
@@ -380,9 +357,8 @@
/**
* Returns a {@code Set} containing all the keys found in this {@code
* Attributes}.
- *
+ *
* @return a {@code Set} of all keys.
- * @since Android 1.0
*/
public Set<Object> keySet() {
return map.keySet();
@@ -390,7 +366,7 @@
/**
* Stores key/value pairs in this {@code Attributes}.
- *
+ *
* @param key
* the key to associate with value.
* @param value
@@ -399,21 +375,20 @@
* @exception ClassCastException
* when key is not an {@code Attributes.Name} or value is not
* a {@code String}.
- *@since Android 1.0
*/
- @SuppressWarnings("cast") // Require cast to force ClassCastException
+ @SuppressWarnings("cast")
+ // Require cast to force ClassCastException
public Object put(Object key, Object value) {
- return map.put((Name)key, (String)value);
+ return map.put((Name) key, (String) value);
}
/**
- * Stores all the key/value pairs in the argument in this {@code Attributes}
- * .
- *
+ * Stores all the key/value pairs in the argument in this {@code
+ * Attributes}.
+ *
* @param attrib
- * the associations to store (must be of type {@code Attributes}
- * ).
- * @since Android 1.0
+ * the associations to store (must be of type {@code
+ * Attributes}).
*/
public void putAll(Map<?, ?> attrib) {
if (attrib == null || !(attrib instanceof Attributes)) {
@@ -425,12 +400,11 @@
/**
* Deletes the key/value pair with key {@code key} from this {@code
* Attributes}.
- *
+ *
* @param key
* the key to remove.
* @return the values associated with the removed key, {@code null} if not
* present.
- * @since Android 1.0
*/
public Object remove(Object key) {
return map.remove(key);
@@ -439,20 +413,18 @@
/**
* Returns the number of key/value pairs associated with this {@code
* Attributes}.
- *
+ *
* @return the size of this {@code Attributes}.
- * @since Android 1.0
*/
public int size() {
return map.size();
}
/**
- * Returns a collection of all the values present in this {@code Attributes}
- * .
- *
+ * Returns a collection of all the values present in this {@code
+ * Attributes}.
+ *
* @return a collection of all values present.
- * @since Android 1.0
*/
public Collection<Object> values() {
return map.values();
@@ -473,9 +445,8 @@
/**
* Returns the hash code of this {@code Attributes}.
- *
+ *
* @return the hash code of this object.
- * @since Android 1.0
*/
@Override
public int hashCode() {
@@ -486,12 +457,11 @@
* Determines if this {@code Attributes} and the parameter {@code
* Attributes} are equal. Two {@code Attributes} instances are equal if they
* contain the same keys and values.
- *
+ *
* @param obj
* the object with which this {@code Attributes} is compared.
* @return {@code true} if the {@code Attributes} are equal, {@code false}
* otherwise.
- * @since Android 1.0
*/
@Override
public boolean equals(Object obj) {
@@ -507,12 +477,11 @@
/**
* Returns the value associated with the parameter {@code Attributes.Name}
* key.
- *
+ *
* @param name
* the key to obtain the value for.
* @return the {@code String} associated with name, or {@code null} if name
* is not a valid key.
- * @since Android 1.0
*/
public String getValue(Attributes.Name name) {
return (String) map.get(name);
@@ -520,12 +489,11 @@
/**
* Returns the string associated with the parameter name.
- *
+ *
* @param name
* the key to obtain the value for.
* @return the string associated with name, or {@code null} if name is not a
* valid key.
- * @since Android 1.0
*/
public String getValue(String name) {
return (String) map.get(new Attributes.Name(name));
@@ -534,13 +502,12 @@
/**
* Stores the value {@code val} associated with the key {@code name} in this
* {@code Attributes}.
- *
+ *
* @param name
* the key to store.
* @param val
* the value to store in this {@code Attributes}.
* @return the value being stored.
- * @since Android 1.0
*/
public String putValue(String name, String val) {
return (String) map.put(new Attributes.Name(name), val);
diff --git a/libcore/archive/src/main/java/java/util/jar/InitManifest.java b/libcore/archive/src/main/java/java/util/jar/InitManifest.java
index 47fdf1c..bf9c397 100644
--- a/libcore/archive/src/main/java/java/util/jar/InitManifest.java
+++ b/libcore/archive/src/main/java/java/util/jar/InitManifest.java
@@ -17,279 +17,206 @@
package java.util.jar;
-import java.io.ByteArrayOutputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.io.UTFDataFormatException;
-import java.security.AccessController;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
import java.util.Map;
import org.apache.harmony.archive.internal.nls.Messages;
-import org.apache.harmony.luni.util.PriviAction;
-import org.apache.harmony.luni.util.Util;
+import org.apache.harmony.luni.util.ThreadLocalCache;
class InitManifest {
- private final byte[] inbuf = new byte[1024];
- private int inbufCount = 0, inbufPos = 0;
+ private byte[] buf;
- private byte[] buffer = new byte[5];
+ private int pos;
- private char[] charbuf = new char[0];
+ Attributes.Name name;
- private final ByteArrayOutputStream out = new ByteArrayOutputStream(256);
+ String value;
- private String encoding;
+ CharsetDecoder decoder = ThreadLocalCache.utf8Decoder.get();
+ CharBuffer cBuf = ThreadLocalCache.charBuffer.get();
- private boolean usingUTF8 = true;
+ InitManifest(byte[] buf, Attributes main, Attributes.Name ver)
+ throws IOException {
- private final Map<String, Attributes.Name> attributeNames = new HashMap<String, Attributes.Name>();
+ this.buf = buf;
- private final byte[] mainAttributesChunk;
-
- InitManifest(InputStream is, Attributes main, Map<String, Attributes> entries, Map<String, byte[]> chunks,
- String verString) throws IOException {
- encoding = AccessController.doPrivileged(new PriviAction<String>(
- "manifest.read.encoding")); //$NON-NLS-1$
- if ("".equals(encoding)) { //$NON-NLS-1$
- encoding = null;
+ // check a version attribute
+ if (!readHeader() || (ver != null && !name.equals(ver))) {
+ throw new IOException(Messages.getString(
+ "archive.2D", ver)); //$NON-NLS-1$
}
- Attributes current = main;
- ArrayList<String> list = new ArrayList<String>();
-
- // Return the chunk of main attributes in the manifest.
- mainAttributesChunk = nextChunk(is, list);
-
- Iterator<String> it = list.iterator();
- while (it.hasNext()) {
- addAttribute(it.next(), current);
+ main.put(name, value);
+ while (readHeader()) {
+ main.put(name, value);
}
+ }
- // Check for version attribute
- if (verString != null && main.getValue(verString) == null) {
- throw new IOException(Messages.getString("archive.2D", verString)); //$NON-NLS-1$
- }
+ void initEntries(Map<String, Attributes> entries,
+ Map<String, Manifest.Chunk> chunks) throws IOException {
- list.clear();
- byte[] chunk = null;
- while (chunks == null ? readLines(is, list) : (chunk = nextChunk(is,
- list)) != null) {
- it = list.iterator();
- String line = it.next();
- if (line.length() < 7
- || !Util.toASCIILowerCase(line.substring(0, 5)).equals("name:")) { //$NON-NLS-1$
+ int mark = pos;
+ while (readHeader()) {
+ if (!Attributes.Name.NAME.equals(name)) {
throw new IOException(Messages.getString("archive.23")); //$NON-NLS-1$
}
- // Name: length required space char
- String name = line.substring(6, line.length());
- current = new Attributes(12);
+ String entryNameValue = value;
+
+ Attributes entry = entries.get(entryNameValue);
+ if (entry == null) {
+ entry = new Attributes(12);
+ }
+
+ while (readHeader()) {
+ entry.put(name, value);
+ }
+
if (chunks != null) {
- chunks.put(name, chunk);
- }
- entries.put(name, current);
- while (it.hasNext()) {
- addAttribute(it.next(), current);
- }
- list.clear();
- }
-
- }
-
- byte[] getMainAttributesChunk() {
- return mainAttributesChunk;
- }
-
- private void addLine(int length, List<String> lines) throws IOException {
- if (encoding != null) {
- lines.add(new String(buffer, 0, length, encoding));
- } else {
- if (usingUTF8) {
- try {
- if (charbuf.length < length) {
- charbuf = new char[length];
- }
- lines.add(Util.convertUTF8WithBuf(buffer, charbuf, 0,
- length));
- } catch (UTFDataFormatException e) {
- usingUTF8 = false;
+ if (chunks.get(entryNameValue) != null) {
+ // TODO A bug: there might be several verification chunks for
+ // the same name. I believe they should be used to update
+ // signature in order of appearance; there are two ways to fix
+ // this: either use a list of chunks, or decide on used
+ // signature algorithm in advance and reread the chunks while
+ // updating the signature; for now a defensive error is thrown
+ throw new IOException(Messages.getString("archive.34")); //$NON-NLS-1$
}
+ chunks.put(entryNameValue, new Manifest.Chunk(mark, pos));
+ mark = pos;
}
- if (!usingUTF8) {
- if (charbuf.length < length) {
- charbuf = new char[length];
- }
- // If invalid UTF8, convert bytes to chars setting the upper
- // bytes to zeros
- int charOffset = 0;
- int offset = 0;
- for (int i = length; --i >= 0;) {
- charbuf[charOffset++] = (char) (buffer[offset++] & 0xff);
- }
- lines.add(new String(charbuf, 0, length));
- }
+
+ entries.put(entryNameValue, entry);
}
}
- private byte[] nextChunk(InputStream in, List<String> lines)
- throws IOException {
- if (inbufCount == -1) {
- return null;
- }
- byte next;
- int pos = 0;
- boolean blankline = false, lastCr = false;
- out.reset();
- while (true) {
- if (inbufPos == inbufCount) {
- if ((inbufCount = in.read(inbuf)) == -1) {
- if (out.size() == 0) {
- return null;
- }
- if (blankline) {
- addLine(pos, lines);
- }
- return out.toByteArray();
- }
- if (inbufCount == inbuf.length && in.available() == 0) {
- /* archive.2E = "line too long" */
- throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
- }
- inbufPos = 0;
- }
- next = inbuf[inbufPos++];
- if (lastCr) {
- if (next != '\n') {
- inbufPos--;
- next = '\r';
- } else {
- if (out.size() == 0) {
- continue;
- }
- out.write('\r');
- }
- lastCr = false;
- } else if (next == '\r') {
- lastCr = true;
- continue;
- }
- if (blankline) {
- if (next == ' ') {
- out.write(next);
- blankline = false;
- continue;
- }
- addLine(pos, lines);
- if (next == '\n') {
- out.write(next);
- return out.toByteArray();
- }
- pos = 0;
- } else if (next == '\n') {
- if (out.size() == 0) {
- continue;
- }
- out.write(next);
- blankline = true;
- continue;
- }
- blankline = false;
- out.write(next);
- if (pos == buffer.length) {
- byte[] newBuf = new byte[buffer.length * 2];
- System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
- buffer = newBuf;
- }
- buffer[pos++] = next;
- }
+ int getPos() {
+ return pos;
}
- private boolean readLines(InputStream in, List<String> lines)
- throws IOException {
- if (inbufCount == -1) {
+ /**
+ * Number of subsequent line breaks.
+ */
+ int linebreak = 0;
+
+ /**
+ * Read a single line from the manifest buffer.
+ */
+ private boolean readHeader() throws IOException {
+ if (linebreak > 1) {
+ // break a section on an empty line
+ linebreak = 0;
return false;
}
- byte next;
- int pos = 0;
- boolean blankline = false, lastCr = false;
- while (true) {
- if (inbufPos == inbufCount) {
- if ((inbufCount = in.read(inbuf)) == -1) {
- if (blankline) {
- addLine(pos, lines);
- }
- return lines.size() != 0;
+ readName();
+ linebreak = 0;
+ readValue();
+ // if the last line break is missed, the line
+ // is ignored by the reference implementation
+ return linebreak > 0;
+ }
+
+ private byte[] wrap(int mark, int pos) {
+ byte[] buffer = new byte[pos - mark];
+ System.arraycopy(buf, mark, buffer, 0, pos - mark);
+ return buffer;
+ }
+
+ private void readName() throws IOException {
+ int i = 0;
+ int mark = pos;
+
+ while (pos < buf.length) {
+ byte b = buf[pos++];
+
+ if (b == ':') {
+ byte[] nameBuffer = wrap(mark, pos - 1);
+
+ if (buf[pos++] != ' ') {
+ throw new IOException(Messages.getString(
+ "archive.30", nameBuffer)); //$NON-NLS-1$
}
- if (inbufCount == inbuf.length && in.available() == 0) {
- /* archive.2E = "line too long" */
- throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
- }
- inbufPos = 0;
+
+ name = new Attributes.Name(nameBuffer);
+ return;
}
- next = inbuf[inbufPos++];
- if (lastCr) {
- if (next != '\n') {
- inbufPos--;
- next = '\r';
- }
- lastCr = false;
- } else if (next == '\r') {
- lastCr = true;
- continue;
+
+ if (!((b >= 'a' && b <= 'z') || (b >= 'A' && b <= 'Z') || b == '_'
+ || b == '-' || (b >= '0' && b <= '9'))) {
+ throw new IOException(Messages.getString("archive.30", b)); //$NON-NLS-1$
}
- if (blankline) {
- if (next == ' ') {
- blankline = false;
- continue;
- }
- addLine(pos, lines);
- if (next == '\n') {
- return true;
- }
- pos = 0;
- } else if (next == '\n') {
- if (pos == 0 && lines.size() == 0) {
- continue;
- }
- blankline = true;
- continue;
- }
- blankline = false;
- if (pos == buffer.length) {
- byte[] newBuf = new byte[buffer.length * 2];
- System.arraycopy(buffer, 0, newBuf, 0, buffer.length);
- buffer = newBuf;
- }
- buffer[pos++] = next;
+ }
+ if (i > 0) {
+ throw new IOException(Messages.getString(
+ "archive.30", wrap(mark, buf.length))); //$NON-NLS-1$
}
}
- /* Get the next attribute and add it */
- private void addAttribute(String line, Attributes current)
- throws IOException {
- String header;
- int hdrIdx = line.indexOf(':');
- if (hdrIdx < 1) {
- throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
- }
- header = line.substring(0, hdrIdx);
- Attributes.Name name = attributeNames.get(header);
- if (name == null) {
- try {
- name = new Attributes.Name(header);
- } catch (IllegalArgumentException e) {
- throw new IOException(e.toString());
+ private void readValue() throws IOException {
+ byte next;
+ boolean lastCr = false;
+ int mark = pos;
+ int last = pos;
+
+ decoder.reset();
+ cBuf.clear();
+
+ while (pos < buf.length) {
+ next = buf[pos++];
+
+ switch (next) {
+ case 0:
+ throw new IOException(Messages.getString("archive.2F")); //$NON-NLS-1$
+ case '\n':
+ if (lastCr) {
+ lastCr = false;
+ } else {
+ linebreak++;
+ }
+ continue;
+ case '\r':
+ lastCr = true;
+ linebreak++;
+ continue;
+ case ' ':
+ if (linebreak == 1) {
+ decode(mark, last, false);
+ mark = pos;
+ linebreak = 0;
+ continue;
+ }
}
- attributeNames.put(header, name);
+
+ if (linebreak >= 1) {
+ pos--;
+ break;
+ }
+ last = pos;
}
- if (hdrIdx + 1 >= line.length() || line.charAt(hdrIdx + 1) != ' ') {
- throw new IOException(Messages.getString("archive.2F", line)); //$NON-NLS-1$
+
+ decode(mark, last, true);
+ while (CoderResult.OVERFLOW == decoder.flush(cBuf)) {
+ enlargeBuffer();
}
- // +2 due to required SPACE char
- current.put(name, line.substring(hdrIdx + 2, line.length()));
+ value = new String(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
+ }
+
+ private void decode(int mark, int pos, boolean endOfInput)
+ throws IOException {
+ ByteBuffer bBuf = ByteBuffer.wrap(buf, mark, pos - mark);
+ while (CoderResult.OVERFLOW == decoder.decode(bBuf, cBuf, endOfInput)) {
+ enlargeBuffer();
+ }
+ }
+
+ private void enlargeBuffer() {
+ CharBuffer newBuf = CharBuffer.allocate(cBuf.capacity() * 2);
+ newBuf.put(cBuf.array(), cBuf.arrayOffset(), cBuf.position());
+ cBuf = newBuf;
+ ThreadLocalCache.charBuffer.set(cBuf);
}
}
diff --git a/libcore/archive/src/main/java/java/util/jar/JarEntry.java b/libcore/archive/src/main/java/java/util/jar/JarEntry.java
index b8dabee..869e4b4 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarEntry.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarEntry.java
@@ -33,27 +33,27 @@
/**
* Represents a single file in a JAR archive together with the manifest
* attributes and digital signatures associated with it.
- *
- * @since Android 1.0
+ *
+ * @see JarFile
+ * @see JarInputStream
*/
public class JarEntry extends ZipEntry {
private Attributes attributes;
JarFile parentJar;
-
+
CodeSigner signers[];
// Cached factory used to build CertPath-s in <code>getCodeSigners()</code>.
private CertificateFactory factory;
- private boolean isFactoryChecked = false;
+ private boolean isFactoryChecked = false;
/**
* Creates a new {@code JarEntry} named name.
*
* @param name
* The name of the new {@code JarEntry}.
- * @since Android 1.0
*/
public JarEntry(String name) {
super(name);
@@ -64,7 +64,6 @@
*
* @param entry
* The ZipEntry to obtain values from.
- * @since Android 1.0
*/
public JarEntry(ZipEntry entry) {
super(entry);
@@ -78,7 +77,6 @@
* @exception IOException
* If an error occurs obtaining the {@code Attributes}.
* @see Attributes
- * @since Android 1.0
*/
public Attributes getAttributes() throws IOException {
if (attributes != null || parentJar == null) {
@@ -99,7 +97,6 @@
*
* @return the certificate for this entry.
* @see java.security.cert.Certificate
- * @since Android 1.0
*/
public Certificate[] getCertificates() {
if (null == parentJar) {
@@ -122,12 +119,11 @@
*
* @param je
* The {@code JarEntry} to obtain values from.
- * @since Android 1.0
*/
public JarEntry(JarEntry je) {
super(je);
parentJar = je.parentJar;
- attributes = je.attributes;
+ attributes = je.attributes;
signers = je.signers;
}
@@ -139,7 +135,6 @@
*
* @return the code signers for the JAR entry.
* @see CodeSigner
- * @since Android 1.0
*/
public CodeSigner[] getCodeSigners() {
if (null == signers) {
@@ -155,7 +150,7 @@
}
private CodeSigner[] getCodeSigners(Certificate[] certs) {
- if(null == certs) {
+ if (null == certs) {
return null;
}
diff --git a/libcore/archive/src/main/java/java/util/jar/JarException.java b/libcore/archive/src/main/java/java/util/jar/JarException.java
index f18d639..d6943c4 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarException.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarException.java
@@ -22,8 +22,6 @@
/**
* This runtime exception is thrown when a problem occurs while reading a JAR
* file.
- *
- * @since Android 1.0
*/
public class JarException extends ZipException {
@@ -31,8 +29,6 @@
/**
* Constructs a new {@code JarException} instance.
- *
- * @since Android 1.0
*/
public JarException() {
super();
@@ -41,10 +37,9 @@
/**
* Constructs a new {@code JarException} instance with the specified
* message.
- *
+ *
* @param detailMessage
* the detail message for the exception.
- * @since Android 1.0
*/
public JarException(String detailMessage) {
super(detailMessage);
diff --git a/libcore/archive/src/main/java/java/util/jar/JarFile.java b/libcore/archive/src/main/java/java/util/jar/JarFile.java
index 9af9056..d6e8339 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarFile.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarFile.java
@@ -29,7 +29,6 @@
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.security.MessageDigest;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
@@ -39,17 +38,14 @@
/**
* {@code JarFile} is used to read jar entries and their associated data from
* jar files.
- *
+ *
* @see JarInputStream
* @see JarEntry
- * @since Android 1.0
*/
public class JarFile extends ZipFile {
/**
* The MANIFEST file name.
- *
- * @since Android 1.0
*/
public static final String MANIFEST_NAME = "META-INF/MANIFEST.MF"; //$NON-NLS-1$
@@ -70,63 +66,69 @@
private ZipEntry zipEntry;
- private JarVerifier verifier;
-
private JarVerifier.VerifierEntry entry;
- private MessageDigest digest;
-
- JarFileInputStream(InputStream is, ZipEntry ze, JarVerifier ver) {
+ JarFileInputStream(InputStream is, ZipEntry ze,
+ JarVerifier.VerifierEntry e) {
super(is);
- if (ver != null) {
- zipEntry = ze;
- verifier = ver;
- count = zipEntry.getSize();
- entry = verifier.initEntry(ze.getName());
- if (entry != null) {
- digest = entry.digest;
- }
- }
+ zipEntry = ze;
+ count = zipEntry.getSize();
+ entry = e;
}
@Override
public int read() throws IOException {
- int r = super.read();
- if (entry != null) {
+ if (count > 0) {
+ int r = super.read();
if (r != -1) {
- digest.update((byte) r);
+ entry.write(r);
count--;
+ } else {
+ count = 0;
}
- if (r == -1 || count <= 0) {
- JarVerifier.VerifierEntry temp = entry;
- entry = null;
- verifier.verifySignatures(temp, zipEntry);
+ if (count == 0) {
+ entry.verify();
}
+ return r;
+ } else {
+ return -1;
}
- return r;
}
@Override
public int read(byte[] buf, int off, int nbytes) throws IOException {
- int r = super.read(buf, off, nbytes);
- if (entry != null) {
+ if (count > 0) {
+ int r = super.read(buf, off, nbytes);
if (r != -1) {
int size = r;
if (count < size) {
size = (int) count;
}
- digest.update(buf, off, size);
- count -= r;
+ entry.write(buf, off, size);
+ count -= size;
+ } else {
+ count = 0;
}
- if (r == -1 || count <= 0) {
- JarVerifier.VerifierEntry temp = entry;
- entry = null;
- verifier.verifySignatures(temp, zipEntry);
+ if (count == 0) {
+ entry.verify();
}
+ return r;
+ } else {
+ return -1;
}
- return r;
}
+ // BEGIN android-added
+ @Override
+ public int available() throws IOException {
+ if (count > 0) {
+ return super.available();
+ } else {
+ return 0;
+ }
+ }
+ // END android-added
+
@Override
public long skip(long nbytes) throws IOException {
long cnt = 0, rem = 0;
@@ -146,12 +148,11 @@
/**
* Create a new {@code JarFile} using the contents of the specified file.
- *
+ *
* @param file
* the JAR file as {@link File}.
* @throws IOException
* If the file cannot be read.
- * @since Android 1.0
*/
public JarFile(File file) throws IOException {
this(file, true);
@@ -159,14 +160,13 @@
/**
* Create a new {@code JarFile} using the contents of the specified file.
- *
+ *
* @param file
* the JAR file as {@link File}.
* @param verify
* if this JAR file is signed whether it must be verified.
* @throws IOException
* If the file cannot be read.
- * @since Android 1.0
*/
public JarFile(File file, boolean verify) throws IOException {
super(file);
@@ -178,7 +178,7 @@
/**
* Create a new {@code JarFile} using the contents of file.
- *
+ *
* @param file
* the JAR file as {@link File}.
* @param verify
@@ -188,7 +188,6 @@
* {@link ZipFile#OPEN_DELETE OPEN_DELETE}.
* @throws IOException
* If the file cannot be read.
- * @since Android 1.0
*/
public JarFile(File file, boolean verify, int mode) throws IOException {
super(file, mode);
@@ -201,12 +200,11 @@
/**
* Create a new {@code JarFile} from the contents of the file specified by
* filename.
- *
+ *
* @param filename
* the file name referring to the JAR file.
* @throws IOException
* if file name cannot be opened for reading.
- * @since Android 1.0
*/
public JarFile(String filename) throws IOException {
this(filename, true);
@@ -216,14 +214,13 @@
/**
* Create a new {@code JarFile} from the contents of the file specified by
* {@code filename}.
- *
+ *
* @param filename
* the file name referring to the JAR file.
* @param verify
* if this JAR filed is signed whether it must be verified.
* @throws IOException
* If file cannot be opened or read.
- * @since Android 1.0
*/
public JarFile(String filename, boolean verify) throws IOException {
super(filename);
@@ -236,11 +233,10 @@
/**
* Return an enumeration containing the {@code JarEntrys} contained in this
* {@code JarFile}.
- *
+ *
* @return the {@code Enumeration} containing the JAR entries.
* @throws IllegalStateException
* if this {@code JarFile} is closed.
- * @since Android 1.0
*/
@Override
public Enumeration<JarEntry> entries() {
@@ -260,7 +256,7 @@
public JarEntry nextElement() {
JarEntry je = new JarEntry(ze.nextElement());
- je.parentJar = jf;
+ je.parentJar = jf;
return je;
}
}
@@ -270,11 +266,10 @@
/**
* Return the {@code JarEntry} specified by its name or {@code null} if no
* such entry exists.
- *
+ *
* @param name
* the name of the entry in the JAR file.
* @return the JAR entry defined by the name.
- * @since Android 1.0
*/
public JarEntry getJarEntry(String name) {
return (JarEntry) getEntry(name);
@@ -302,14 +297,13 @@
/**
* Returns the {@code Manifest} object associated with this {@code JarFile}
* or {@code null} if no MANIFEST entry exists.
- *
+ *
* @return the MANIFEST.
* @throws IOException
* if an error occurs reading the MANIFEST file.
* @throws IllegalStateException
* if the jar file is closed.
* @see Manifest
- * @since Android 1.0
*/
public Manifest getManifest() throws IOException {
// BEGIN android-added
@@ -358,10 +352,14 @@
if (verifier == null) {
break;
}
- } else if (verifier != null && entryName.length() > dirLength
- && (Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 3, ".SF", 0 ,3) //$NON-NLS-1$
- || Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 4, ".DSA", 0 ,4) //$NON-NLS-1$
- || Util.ASCIIIgnoreCaseRegionMatches(entryName, entryName.length() - 4, ".RSA", 0 ,4))){ //$NON-NLS-1$
+ } else if (verifier != null
+ && entryName.length() > dirLength
+ && (Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ entryName.length() - 3, ".SF", 0, 3) //$NON-NLS-1$
+ || Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ entryName.length() - 4, ".DSA", 0, 4) //$NON-NLS-1$
+ || Util.ASCIIIgnoreCaseRegionMatches(entryName,
+ entryName.length() - 4, ".RSA", 0, 4))) { //$NON-NLS-1$
signed = true;
InputStream is = super.getInputStream(entry);
// BEGIN android-modified
@@ -379,13 +377,12 @@
/**
* Return an {@code InputStream} for reading the decompressed contents of
* ZIP entry.
- *
+ *
* @param ze
* the ZIP entry to be read.
* @return the input stream to read from.
* @throws IOException
* if an error occurred while creating the input stream.
- * @since Android 1.0
*/
@Override
public InputStream getInputStream(ZipEntry ze) throws IOException {
@@ -395,8 +392,7 @@
if (verifier != null) {
verifier.setManifest(getManifest());
if (manifest != null) {
- verifier.mainAttributesChunk = manifest
- .getMainAttributesChunk();
+ verifier.mainAttributesEnd = manifest.getMainAttributesEnd();
}
if (verifier.readCertificates()) {
verifier.removeMetaEntries();
@@ -412,19 +408,24 @@
if (in == null) {
return null;
}
- return new JarFileInputStream(in, ze, ze.getSize() >= 0 ? verifier
- : null);
+ if (verifier == null || ze.getSize() == -1) {
+ return in;
+ }
+ JarVerifier.VerifierEntry entry = verifier.initEntry(ze.getName());
+ if (entry == null) {
+ return in;
+ }
+ return new JarFileInputStream(in, ze, entry);
}
/**
* Return the {@code JarEntry} specified by name or {@code null} if no such
* entry exists.
- *
+ *
* @param name
* the name of the entry in the JAR file.
* @return the ZIP entry extracted.
- * @since Android 1.0
- */
+ */
@Override
public ZipEntry getEntry(String name) {
ZipEntry ze = super.getEntry(name);
@@ -432,16 +433,16 @@
return ze;
}
JarEntry je = new JarEntry(ze);
- je.parentJar = this;
+ je.parentJar = this;
return je;
}
// BEGIN android-modified
private ZipEntry[] getMetaEntriesImpl(byte[] buf) {
int n = 0;
-
+
List<ZipEntry> list = new ArrayList<ZipEntry>();
-
+
Enumeration<? extends ZipEntry> allEntries = entries();
while (allEntries.hasMoreElements()) {
ZipEntry ze = allEntries.nextElement();
@@ -463,10 +464,9 @@
// BEGIN android-added
/**
* Closes this {@code JarFile}.
- *
+ *
* @throws IOException
* if an error occurs.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/jar/JarInputStream.java b/libcore/archive/src/main/java/java/util/jar/JarInputStream.java
index ef353ab..c803183 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarInputStream.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarInputStream.java
@@ -24,14 +24,13 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
-import org.apache.harmony.archive.util.Util;
+import org.apache.harmony.luni.util.Util;
/**
* The input stream from which the JAR file to be read may be fetched. It is
* used like the {@code ZipInputStream}.
- *
+ *
* @see ZipInputStream
- * @since Android 1.0
*/
public class JarInputStream extends ZipInputStream {
@@ -51,7 +50,7 @@
/**
* Constructs a new {@code JarInputStream} from an input stream.
- *
+ *
* @param stream
* the input stream containing the JAR file.
* @param verify
@@ -59,7 +58,6 @@
* @throws IOException
* If an error occurs reading entries from the input stream.
* @see ZipInputStream#ZipInputStream(InputStream)
- * @since Android 1.0
*/
public JarInputStream(InputStream stream, boolean verify)
throws IOException {
@@ -84,8 +82,8 @@
if (verify) {
verifier.setManifest(manifest);
if (manifest != null) {
- verifier.mainAttributesChunk = manifest
- .getMainAttributesChunk();
+ verifier.mainAttributesEnd = manifest
+ .getMainAttributesEnd();
}
}
@@ -103,13 +101,12 @@
/**
* Constructs a new {@code JarInputStream} from an input stream.
- *
+ *
* @param stream
* the input stream containing the JAR file.
* @throws IOException
* If an error occurs reading entries from the input stream.
* @see ZipInputStream#ZipInputStream(InputStream)
- * @since Android 1.0
*/
public JarInputStream(InputStream stream) throws IOException {
this(stream, true);
@@ -120,7 +117,6 @@
* JarInputStream} or {@code null} if no manifest entry exists.
*
* @return the MANIFEST specifying the contents of the JAR file.
- * @since Android 1.0
*/
public Manifest getManifest() {
return manifest;
@@ -133,7 +129,6 @@
* @return the next JAR entry.
* @throws IOException
* if an error occurs while reading the entry.
- * @since Android 1.0
*/
public JarEntry getNextJarEntry() throws IOException {
return (JarEntry) getNextEntry();
@@ -142,7 +137,7 @@
/**
* Reads up to {@code length} of decompressed data and stores it in
* {@code buffer} starting at {@code offset}.
- *
+ *
* @param buffer
* Buffer to store into
* @param offset
@@ -152,7 +147,6 @@
* @return Number of uncompressed bytes read
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
@Override
public int read(byte[] buffer, int offset, int length) throws IOException {
@@ -175,9 +169,7 @@
throw e;
}
} else {
- verifier.verifySignatures(
- (JarVerifier.VerifierEntry) verStream,
- jarEntry);
+ ((JarVerifier.VerifierEntry) verStream).verify();
}
}
} else {
@@ -194,7 +186,6 @@
* @return the next extracted ZIP entry.
* @throws IOException
* if an error occurs while reading the entry.
- * @since Android 1.0
*/
@Override
public ZipEntry getNextEntry() throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/jar/JarOutputStream.java b/libcore/archive/src/main/java/java/util/jar/JarOutputStream.java
index 640f4ef..e901d87 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarOutputStream.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarOutputStream.java
@@ -25,8 +25,6 @@
/**
* The {@code JarOutputStream} is used to write data in the {@code JarFile}
* format to an arbitrary output stream
- *
- * @since Android 1.0
*/
public class JarOutputStream extends ZipOutputStream {
@@ -79,7 +77,6 @@
* @throws IOException
* if an error occurs writing to the entry.
* @see ZipEntry
- * @since Android 1.0
*/
@Override
public void putNextEntry(ZipEntry ze) throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/jar/JarVerifier.java b/libcore/archive/src/main/java/java/util/jar/JarVerifier.java
index b9173f2..6c1ee93 100644
--- a/libcore/archive/src/main/java/java/util/jar/JarVerifier.java
+++ b/libcore/archive/src/main/java/java/util/jar/JarVerifier.java
@@ -31,13 +31,12 @@
import java.util.Map;
import java.util.StringTokenizer;
import java.util.Vector;
-import java.util.zip.ZipEntry;
import org.apache.harmony.archive.internal.nls.Messages;
import org.apache.harmony.luni.util.Base64;
import org.apache.harmony.security.utils.JarUtils;
-import org.apache.harmony.archive.util.Util;
+import org.apache.harmony.luni.util.Util;
// BEGIN android-added
import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigestJDK;
@@ -65,65 +64,81 @@
private HashMap<String, byte[]> metaEntries = new HashMap<String, byte[]>(5);
- private final Hashtable<String, HashMap<String, Attributes>> signatures =
- new Hashtable<String, HashMap<String, Attributes>>(5);
+ private final Hashtable<String, HashMap<String, Attributes>> signatures = new Hashtable<String, HashMap<String, Attributes>>(
+ 5);
- private final Hashtable<String, Certificate[]> certificates =
- new Hashtable<String, Certificate[]>(5);
+ private final Hashtable<String, Certificate[]> certificates = new Hashtable<String, Certificate[]>(
+ 5);
- private final Hashtable<String, Certificate[]> verifiedEntries =
- new Hashtable<String, Certificate[]>();
+ private final Hashtable<String, Certificate[]> verifiedEntries = new Hashtable<String, Certificate[]>();
- byte[] mainAttributesChunk;
+ int mainAttributesEnd;
- // BEGIN android-added
- private static long measureCount = 0;
-
- private static long averageTime = 0;
- // END android-added
-
/**
- * TODO Type description
+ * Stores and a hash and a message digest and verifies that massage digest
+ * matches the hash.
*/
- static class VerifierEntry extends OutputStream {
+ class VerifierEntry extends OutputStream {
- MessageDigest digest;
+ private String name;
- byte[] hash;
+ private MessageDigest digest;
- Certificate[] certificates;
+ private byte[] hash;
- VerifierEntry(MessageDigest digest, byte[] hash,
+ private Certificate[] certificates;
+
+ VerifierEntry(String name, MessageDigest digest, byte[] hash,
Certificate[] certificates) {
+ this.name = name;
this.digest = digest;
this.hash = hash;
this.certificates = certificates;
}
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(int)
+ /**
+ * Updates a digest with one byte.
*/
@Override
public void write(int value) {
digest.update((byte) value);
}
- /*
- * (non-Javadoc)
- *
- * @see java.io.OutputStream#write(byte[], int, int)
+ /**
+ * Updates a digest with byte array.
*/
@Override
public void write(byte[] buf, int off, int nbytes) {
digest.update(buf, off, nbytes);
}
+
+ /**
+ * Verifies that the digests stored in the manifest match the decrypted
+ * digests from the .SF file. This indicates the validity of the
+ * signing, not the integrity of the file, as it's digest must be
+ * calculated and verified when its contents are read.
+ *
+ * @throws SecurityException
+ * if the digest value stored in the manifest does <i>not</i>
+ * agree with the decrypted digest as recovered from the
+ * <code>.SF</code> file.
+ * @see #initEntry(String)
+ */
+ void verify() {
+ byte[] d = digest.digest();
+ if (!MessageDigest.isEqual(d, Base64.decode(hash))) {
+ throw new SecurityException(Messages.getString(
+ "archive.32", new Object[] { //$NON-NLS-1$
+ JarFile.MANIFEST_NAME, name, jarName }));
+ }
+ verifiedEntries.put(name, certificates);
+ }
+
}
/**
* Constructs and returns a new instance of {@code JarVerifier}.
- *
+ *
* @param name
* the name of the JAR file being verified.
*/
@@ -136,13 +151,12 @@
* stream. This method constructs and returns a new {@link VerifierEntry}
* which contains the certificates used to sign the entry and its hash value
* as specified in the JAR MANIFEST format.
- *
+ *
* @param name
* the name of an entry in a JAR file which is <b>not</b> in the
* {@code META-INF} directory.
* @return a new instance of {@link VerifierEntry} which can be used by
* callers as an {@link OutputStream}.
- * @since Android 1.0
*/
VerifierEntry initEntry(String name) {
// If no manifest is present by the time an entry is found,
@@ -159,8 +173,8 @@
}
Vector<Certificate> certs = new Vector<Certificate>();
- Iterator<Map.Entry<String, HashMap<String, Attributes>>> it =
- signatures.entrySet().iterator();
+ Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures
+ .entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
HashMap<String, Attributes> hm = entry.getValue();
@@ -197,18 +211,18 @@
}
byte[] hashBytes;
try {
- hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ hashBytes = hash.getBytes("ISO-8859-1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
try {
// BEGIN android-changed
- return new VerifierEntry(OpenSSLMessageDigestJDK.getInstance(algorithm),
+ return new VerifierEntry(name, OpenSSLMessageDigestJDK.getInstance(algorithm),
hashBytes, certificatesArray);
// END android-changed
} catch (NoSuchAlgorithmException e) {
- // Ignored
+ // ignored
}
}
return null;
@@ -219,7 +233,7 @@
* entry in the {@code META-INF} directory including the manifest
* file itself. Files associated with the signing of a JAR would also be
* added to this collection.
- *
+ *
* @param name
* the name of the file located in the {@code META-INF}
* directory.
@@ -234,7 +248,7 @@
/**
* If the associated JAR file is signed, check on the validity of all of the
* known signatures.
- *
+ *
* @return {@code true} if the associated JAR is signed and an internal
* check verifies the validity of the signature(s). {@code false} if
* the associated JAR file has no entries at all in its {@code
@@ -243,12 +257,10 @@
* <p>
* Will also return {@code true} if the JAR file is <i>not</i>
* signed.
- * </p>
* @throws SecurityException
* if the JAR file is signed and it is determined that a
* signature block file contains an invalid signature for the
* corresponding signature file.
- * @since Android 1.0
*/
synchronized boolean readCertificates() {
if (metaEntries == null) {
@@ -281,6 +293,12 @@
return;
}
+ byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
+ // Manifest entry is required for any verifications.
+ if (manifest == null) {
+ return;
+ }
+
byte[] sBlockBytes = metaEntries.get(certFile);
try {
Certificate[] signerCertChain = JarUtils.verifySignature(
@@ -288,7 +306,7 @@
new ByteArrayInputStream(sBlockBytes));
/*
* Recursive call in loading security provider related class which
- * is in a signed JAR.
+ * is in a signed JAR.
*/
if (null == metaEntries) {
return;
@@ -299,74 +317,70 @@
} catch (IOException e) {
return;
} catch (GeneralSecurityException e) {
- /* [MSG "archive.30", "{0} failed verification of {1}"] */
- throw new SecurityException(
- Messages.getString("archive.30", jarName, signatureFile)); //$NON-NLS-1$
+ /* [MSG "archive.31", "{0} failed verification of {1}"] */
+ throw new SecurityException(Messages.getString(
+ "archive.31", jarName, signatureFile)); //$NON-NLS-1$
}
// Verify manifest hash in .sf file
Attributes attributes = new Attributes();
- HashMap<String, Attributes> hm = new HashMap<String, Attributes>();
+ HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
try {
- new InitManifest(new ByteArrayInputStream(sfBytes), attributes, hm,
- null, "Signature-Version"); //$NON-NLS-1$
+ InitManifest im = new InitManifest(sfBytes, attributes, Attributes.Name.SIGNATURE_VERSION);
+ im.initEntries(entries, null);
} catch (IOException e) {
return;
}
boolean createdBySigntool = false;
- String createdByValue = attributes.getValue("Created-By"); //$NON-NLS-1$
- if (createdByValue != null) {
- createdBySigntool = createdByValue.indexOf("signtool") != -1; //$NON-NLS-1$
+ String createdBy = attributes.getValue("Created-By"); //$NON-NLS-1$
+ if (createdBy != null) {
+ createdBySigntool = createdBy.indexOf("signtool") != -1; //$NON-NLS-1$
}
// Use .SF to verify the mainAttributes of the manifest
// If there is no -Digest-Manifest-Main-Attributes entry in .SF
// file, such as those created before java 1.5, then we ignore
// such verification.
- // FIXME: The meaning of createdBySigntool
- if (mainAttributesChunk != null && !createdBySigntool) {
+ if (mainAttributesEnd > 0 && !createdBySigntool) {
String digestAttribute = "-Digest-Manifest-Main-Attributes"; //$NON-NLS-1$
- if (!verify(attributes, digestAttribute, mainAttributesChunk,
- false, true)) {
- /* [MSG "archive.30", "{0} failed verification of {1}"] */
- throw new SecurityException(
- Messages.getString("archive.30", jarName, signatureFile)); //$NON-NLS-1$
+ if (!verify(attributes, digestAttribute, manifest, 0,
+ mainAttributesEnd, false, true)) {
+ /* [MSG "archive.31", "{0} failed verification of {1}"] */
+ throw new SecurityException(Messages.getString(
+ "archive.31", jarName, signatureFile)); //$NON-NLS-1$
}
}
- byte[] manifest = metaEntries.get(JarFile.MANIFEST_NAME);
- if (manifest == null) {
- return;
- }
- // Use .SF to verify the whole manifest
+ // Use .SF to verify the whole manifest.
String digestAttribute = createdBySigntool ? "-Digest" //$NON-NLS-1$
: "-Digest-Manifest"; //$NON-NLS-1$
- if (!verify(attributes, digestAttribute, manifest, false, false)) {
- Iterator<Map.Entry<String, Attributes>> it = hm.entrySet()
+ if (!verify(attributes, digestAttribute, manifest, 0, manifest.length,
+ false, false)) {
+ Iterator<Map.Entry<String, Attributes>> it = entries.entrySet()
.iterator();
while (it.hasNext()) {
Map.Entry<String, Attributes> entry = it.next();
- byte[] chunk = man.getChunk(entry.getKey());
+ Manifest.Chunk chunk = man.getChunk(entry.getKey());
if (chunk == null) {
return;
}
- if (!verify(entry.getValue(), "-Digest", chunk, //$NON-NLS-1$
- createdBySigntool, false)) {
- /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
- throw new SecurityException(
- Messages.getString("archive.31", //$NON-NLS-1$
- new Object[] { signatureFile, entry.getKey(), jarName }));
+ if (!verify(entry.getValue(), "-Digest", manifest, //$NON-NLS-1$
+ chunk.start, chunk.end, createdBySigntool, false)) {
+ throw new SecurityException(Messages.getString(
+ "archive.32", //$NON-NLS-1$
+ new Object[] { signatureFile, entry.getKey(),
+ jarName }));
}
}
}
metaEntries.put(signatureFile, null);
- signatures.put(signatureFile, hm);
+ signatures.put(signatureFile, entries);
}
/**
* Associate this verifier with the specified {@link Manifest} object.
- *
+ *
* @param mf
* a {@code java.util.jar.Manifest} object.
*/
@@ -375,36 +389,9 @@
}
/**
- * Verifies that the digests stored in the manifest match the decrypted
- * digests from the .SF file. This indicates the validity of the signing,
- * not the integrity of the file, as it's digest must be calculated and
- * verified when its contents are read.
- *
- * @param entry
- * the {@link VerifierEntry} associated with the specified
- * {@code zipEntry}.
- * @param zipEntry
- * an entry in the JAR file
- * @throws SecurityException
- * if the digest value stored in the manifest does <i>not</i>
- * agree with the decrypted digest as recovered from the
- * {@code .SF} file.
- * @see #initEntry(String)
- */
- void verifySignatures(VerifierEntry entry, ZipEntry zipEntry) {
- byte[] digest = entry.digest.digest();
- if (!MessageDigest.isEqual(digest, Base64.decode(entry.hash))) {
- /* [MSG "archive.31", "{0} has invalid digest for {1} in {2}"] */
- throw new SecurityException(Messages.getString("archive.31", new Object[] { //$NON-NLS-1$
- JarFile.MANIFEST_NAME, zipEntry.getName(), jarName }));
- }
- verifiedEntries.put(zipEntry.getName(), entry.certificates);
- }
-
- /**
- * Returns a {@code boolean} indication of whether or not the
- * associated JAR file is signed.
- *
+ * Returns a <code>boolean</code> indication of whether or not the
+ * associated jar file is signed.
+ *
* @return {@code true} if the JAR is signed, {@code false}
* otherwise.
*/
@@ -413,7 +400,7 @@
}
private boolean verify(Attributes attributes, String entry, byte[] data,
- boolean ignoreSecondEndline, boolean ignorable) {
+ int start, int end, boolean ignoreSecondEndline, boolean ignorable) {
String algorithms = attributes.getValue("Digest-Algorithms"); //$NON-NLS-1$
if (algorithms == null) {
algorithms = "SHA SHA1"; //$NON-NLS-1$
@@ -434,16 +421,16 @@
} catch (NoSuchAlgorithmException e) {
continue;
}
- if (ignoreSecondEndline && data[data.length - 1] == '\n'
- && data[data.length - 2] == '\n') {
- md.update(data, 0, data.length - 1);
+ if (ignoreSecondEndline && data[end - 1] == '\n'
+ && data[end - 2] == '\n') {
+ md.update(data, start, end - 1 - start);
} else {
- md.update(data, 0, data.length);
+ md.update(data, start, end - start);
}
byte[] b = md.digest();
byte[] hashBytes;
try {
- hashBytes = hash.getBytes("ISO8859_1"); //$NON-NLS-1$
+ hashBytes = hash.getBytes("ISO-8859-1"); //$NON-NLS-1$
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e.toString());
}
@@ -456,7 +443,7 @@
* Returns all of the {@link java.security.cert.Certificate} instances that
* were used to verify the signature on the JAR entry called
* {@code name}.
- *
+ *
* @param name
* the name of a JAR entry.
* @return an array of {@link java.security.cert.Certificate}.
@@ -472,7 +459,7 @@
/**
* Remove all entries from the internal collection of data held about each
* JAR entry in the {@code META-INF} directory.
- *
+ *
* @see #addMetaEntry(String, byte[])
*/
void removeMetaEntries() {
@@ -483,7 +470,7 @@
* Returns a {@code Vector} of all of the
* {@link java.security.cert.Certificate}s that are associated with the
* signing of the named signature file.
- *
+ *
* @param signatureFileName
* the name of a signature file.
* @param certificates
diff --git a/libcore/archive/src/main/java/java/util/jar/Manifest.java b/libcore/archive/src/main/java/java/util/jar/Manifest.java
index 3b0d89a..b28f3fb 100644
--- a/libcore/archive/src/main/java/java/util/jar/Manifest.java
+++ b/libcore/archive/src/main/java/java/util/jar/Manifest.java
@@ -17,47 +17,65 @@
package java.util.jar;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.security.AccessController;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
-import org.apache.harmony.luni.util.PriviAction;
+import org.apache.harmony.archive.internal.nls.Messages;
+import org.apache.harmony.luni.util.InputStreamExposer;
+import org.apache.harmony.luni.util.ThreadLocalCache;
/**
* The {@code Manifest} class is used to obtain attribute information for a
* {@code JarFile} and its entries.
- *
- * @since Android 1.0
*/
public class Manifest implements Cloneable {
- private static final int LINE_LENGTH_LIMIT = 70;
+ static final int LINE_LENGTH_LIMIT = 72;
private static final byte[] LINE_SEPARATOR = new byte[] { '\r', '\n' };
- private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name("Name"); //$NON-NLS-1$
+ private static final byte[] VALUE_SEPARATOR = new byte[] { ':', ' ' };
+
+ private static final Attributes.Name NAME_ATTRIBUTE = new Attributes.Name(
+ "Name"); //$NON-NLS-1$
private Attributes mainAttributes = new Attributes();
- private HashMap<String, Attributes> entryAttributes = new HashMap<String, Attributes>();
+ private HashMap<String, Attributes> entries = new HashMap<String, Attributes>();
- private HashMap<String, byte[]> chunks;
+ static class Chunk {
+ int start;
+ int end;
+
+ Chunk(int start, int end) {
+ this.start = start;
+ this.end = end;
+ }
+ }
+
+ private HashMap<String, Chunk> chunks;
/**
- * The data chunk of main attributes in the manifest is needed in
+ * Manifest bytes are used for delayed entry parsing.
+ */
+ private InitManifest im;
+
+ /**
+ * The end of the main attributes section in the manifest is needed in
* verification.
*/
- private byte[] mainAttributesChunk;
+ private int mainEnd;
/**
* Creates a new {@code Manifest} instance.
- *
- * @since Android 1.0
*/
public Manifest() {
super();
@@ -66,12 +84,11 @@
/**
* Creates a new {@code Manifest} instance using the attributes obtained
* from the input stream.
- *
+ *
* @param is
* {@code InputStream} to parse for attributes.
* @throws IOException
* if an IO error occurs while creating this {@code Manifest}
- * @since Android 1.0
*/
public Manifest(InputStream is) throws IOException {
super();
@@ -81,20 +98,20 @@
/**
* Creates a new {@code Manifest} instance. The new instance will have the
* same attributes as those found in the parameter {@code Manifest}.
- *
+ *
* @param man
* {@code Manifest} instance to obtain attributes from.
- * @since Android 1.0
*/
@SuppressWarnings("unchecked")
public Manifest(Manifest man) {
mainAttributes = (Attributes) man.mainAttributes.clone();
- entryAttributes = (HashMap<String, Attributes>) man.entryAttributes.clone();
+ entries = (HashMap<String, Attributes>) ((HashMap<String, Attributes>) man
+ .getEntries()).clone();
}
Manifest(InputStream is, boolean readChunks) throws IOException {
if (readChunks) {
- chunks = new HashMap<String, byte[]>();
+ chunks = new HashMap<String, Chunk>();
}
read(is);
}
@@ -102,23 +119,21 @@
/**
* Resets the both the main attributes as well as the entry attributes
* associated with this {@code Manifest}.
- *
- * @since Android 1.0
*/
public void clear() {
- entryAttributes.clear();
+ im = null;
+ entries.clear();
mainAttributes.clear();
}
/**
* Returns the {@code Attributes} associated with the parameter entry
* {@code name}.
- *
+ *
* @param name
* the name of the entry to obtain {@code Attributes} from.
* @return the Attributes for the entry or {@code null} if the entry does
* not exist.
- * @since Android 1.0
*/
public Attributes getAttributes(String name) {
return getEntries().get(name);
@@ -127,20 +142,31 @@
/**
* Returns a map containing the {@code Attributes} for each entry in the
* {@code Manifest}.
- *
+ *
* @return the map of entry attributes.
- * @since Android 1.0
*/
public Map<String, Attributes> getEntries() {
- return entryAttributes;
+ initEntries();
+ return entries;
+ }
+
+ private void initEntries() {
+ if (im == null) {
+ return;
+ }
+ // try {
+ // im.initEntries(entries, chunks);
+ // } catch (IOException ioe) {
+ // throw new RuntimeException(ioe);
+ // }
+ // im = null;
}
/**
* Returns the main {@code Attributes} of the {@code JarFile}.
- *
+ *
* @return main {@code Attributes} associated with the source {@code
* JarFile}.
- * @since Android 1.0
*/
public Attributes getMainAttributes() {
return mainAttributes;
@@ -149,9 +175,8 @@
/**
* Creates a copy of this {@code Manifest}. The returned {@code Manifest}
* will equal the {@code Manifest} from which it was cloned.
- *
+ *
* @return a copy of this instance.
- * @since Android 1.0
*/
@Override
public Object clone() {
@@ -161,12 +186,11 @@
/**
* Writes out the attribute information of the receiver to the specified
* {@code OutputStream}.
- *
+ *
* @param os
* The {@code OutputStream} to write to.
* @throws IOException
* If an error occurs writing the {@code Manifest}.
- * @since Android 1.0
*/
public void write(OutputStream os) throws IOException {
write(this, os);
@@ -175,39 +199,98 @@
/**
* Constructs a new {@code Manifest} instance obtaining attribute
* information from the specified input stream.
- *
+ *
* @param is
* The {@code InputStream} to read from.
* @throws IOException
* If an error occurs reading the {@code Manifest}.
- * @since Android 1.0
*/
public void read(InputStream is) throws IOException {
- InitManifest initManifest = new InitManifest(is, mainAttributes, entryAttributes,
- chunks, null);
- mainAttributesChunk = initManifest.getMainAttributesChunk();
+ byte[] buf;
+ // Try to read get a reference to the bytes directly
+ try {
+ buf = InputStreamExposer.expose(is);
+ } catch (UnsupportedOperationException uoe) {
+ buf = readFully(is);
+ }
+
+ if (buf.length == 0) {
+ return;
+ }
+
+ // a workaround for HARMONY-5662
+ // replace EOF and NUL with another new line
+ // which does not trigger an error
+ byte b = buf[buf.length - 1];
+ if (0 == b || 26 == b) {
+ buf[buf.length - 1] = '\n';
+ }
+
+ // Attributes.Name.MANIFEST_VERSION is not used for
+ // the second parameter for RI compatibility
+ im = new InitManifest(buf, mainAttributes, null);
+ mainEnd = im.getPos();
+ // FIXME
+ im.initEntries(entries, chunks);
+ im = null;
+ }
+
+ /*
+ * Helper to read the entire contents of the manifest from the
+ * given input stream. Usually we can do this in a single read
+ * but we need to account for 'infinite' streams, by ensuring we
+ * have a line feed within a reasonable number of characters.
+ */
+ private byte[] readFully(InputStream is) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ byte[] buffer = new byte[8192];
+
+ while (true) {
+ int count = is.read(buffer);
+ if (count == -1) {
+ // TODO: Do we need to copy this, or can we live with junk at the end?
+ return baos.toByteArray();
+ }
+ baos.write(buffer, 0, count);
+
+ if (!containsLine(buffer, count)) {
+ throw new IOException(Messages.getString("archive.2E")); //$NON-NLS-1$
+ }
+ }
+ }
+
+ /*
+ * Check to see if the buffer contains a newline or carriage
+ * return character within the first 'length' bytes. Used to
+ * check the validity of the manifest input stream.
+ */
+ private boolean containsLine(byte[] buffer, int length) {
+ for (int i = 0; i < length; i++) {
+ if (buffer[i] == 0x0A || buffer[i] == 0x0D) {
+ return true;
+ }
+ }
+ return false;
}
/**
* Returns the hash code for this instance.
- *
+ *
* @return this {@code Manifest}'s hashCode.
- * @since Android 1.0
*/
@Override
public int hashCode() {
- return mainAttributes.hashCode() ^ entryAttributes.hashCode();
+ return mainAttributes.hashCode() ^ getEntries().hashCode();
}
/**
* Determines if the receiver is equal to the parameter object. Two {@code
* Manifest}s are equal if they have identical main attributes as well as
* identical entry attributes.
- *
+ *
* @param o
* the object to compare against.
* @return {@code true} if the manifests are equal, {@code false} otherwise
- * @since Android 1.0
*/
@Override
public boolean equals(Object o) {
@@ -220,10 +303,10 @@
if (!mainAttributes.equals(((Manifest) o).mainAttributes)) {
return false;
}
- return entryAttributes.equals(((Manifest) o).entryAttributes);
+ return getEntries().equals(((Manifest) o).getEntries());
}
- byte[] getChunk(String name) {
+ Chunk getChunk(String name) {
return chunks.get(name);
}
@@ -231,114 +314,84 @@
chunks = null;
}
- byte[] getMainAttributesChunk() {
- return mainAttributesChunk;
+ int getMainAttributesEnd() {
+ return mainEnd;
}
/**
* Writes out the attribute information of the specified manifest to the
* specified {@code OutputStream}
- *
+ *
* @param manifest
* the manifest to write out.
* @param out
* The {@code OutputStream} to write to.
* @throws IOException
* If an error occurs writing the {@code Manifest}.
- * @since Android 1.0
*/
static void write(Manifest manifest, OutputStream out) throws IOException {
- Charset charset = null;
- String encoding = AccessController.doPrivileged(new PriviAction<String>(
- "manifest.write.encoding")); //$NON-NLS-1$
- if (encoding != null) {
- if (encoding.length() == 0) {
- encoding = "UTF8"; //$NON-NLS-1$
- }
- charset = Charset.forName(encoding);
- }
- String version = manifest.mainAttributes.getValue(Attributes.Name.MANIFEST_VERSION);
+ CharsetEncoder encoder = ThreadLocalCache.utf8Encoder.get();
+ ByteBuffer buffer = ThreadLocalCache.byteBuffer.get();
+
+ String version = manifest.mainAttributes
+ .getValue(Attributes.Name.MANIFEST_VERSION);
if (version != null) {
- writeEntry(out, charset, Attributes.Name.MANIFEST_VERSION, version);
+ writeEntry(out, Attributes.Name.MANIFEST_VERSION, version, encoder,
+ buffer);
Iterator<?> entries = manifest.mainAttributes.keySet().iterator();
while (entries.hasNext()) {
Attributes.Name name = (Attributes.Name) entries.next();
if (!name.equals(Attributes.Name.MANIFEST_VERSION)) {
- writeEntry(out, charset, name, manifest.mainAttributes.getValue(name));
+ writeEntry(out, name, manifest.mainAttributes
+ .getValue(name), encoder, buffer);
}
}
}
out.write(LINE_SEPARATOR);
- Iterator<String> i = manifest.entryAttributes.keySet().iterator();
+ Iterator<String> i = manifest.getEntries().keySet().iterator();
while (i.hasNext()) {
String key = i.next();
- writeEntry(out, charset, NAME_ATTRIBUTE, key);
- Attributes attrib = manifest.entryAttributes.get(key);
+ writeEntry(out, NAME_ATTRIBUTE, key, encoder, buffer);
+ Attributes attrib = manifest.entries.get(key);
Iterator<?> entries = attrib.keySet().iterator();
while (entries.hasNext()) {
Attributes.Name name = (Attributes.Name) entries.next();
- writeEntry(out, charset, name, attrib.getValue(name));
+ writeEntry(out, name, attrib.getValue(name), encoder, buffer);
}
out.write(LINE_SEPARATOR);
}
}
- private static void writeEntry(OutputStream os, Charset charset, Attributes.Name name,
- String value) throws IOException {
- int offset = 0;
- int limit = LINE_LENGTH_LIMIT;
- byte[] out = (name.toString() + ": ").getBytes("ISO8859_1"); //$NON-NLS-1$ //$NON-NLS-2$
- if (out.length > limit) {
- while (out.length - offset >= limit) {
- int len = out.length - offset;
- if (len > limit) {
- len = limit;
- }
- if (offset > 0) {
- os.write(' ');
- }
- os.write(out, offset, len);
- os.write(LINE_SEPARATOR);
- offset += len;
- limit = LINE_LENGTH_LIMIT - 1;
- }
+ private static void writeEntry(OutputStream os, Attributes.Name name,
+ String value, CharsetEncoder encoder, ByteBuffer bBuf)
+ throws IOException {
+ byte[] out = name.getBytes();
+ if (out.length > LINE_LENGTH_LIMIT) {
+ throw new IOException(Messages.getString(
+ "archive.33", name, Integer.valueOf(LINE_LENGTH_LIMIT))); //$NON-NLS-1$
}
- int size = out.length - offset;
- final byte[] outBuf = new byte[LINE_LENGTH_LIMIT];
- System.arraycopy(out, offset, outBuf, 0, size);
- for (int i = 0; i < value.length(); i++) {
- char[] oneChar = new char[1];
- oneChar[0] = value.charAt(i);
- byte[] buf;
- if (oneChar[0] < 128 || charset == null) {
- byte[] oneByte = new byte[1];
- oneByte[0] = (byte) oneChar[0];
- buf = oneByte;
- } else {
- buf = charset.encode(CharBuffer.wrap(oneChar, 0, 1)).array();
+
+ os.write(out);
+ os.write(VALUE_SEPARATOR);
+
+ encoder.reset();
+ bBuf.clear().limit(LINE_LENGTH_LIMIT - out.length - 2);
+
+ CharBuffer cBuf = CharBuffer.wrap(value);
+ CoderResult r;
+
+ while (true) {
+ r = encoder.encode(cBuf, bBuf, true);
+ if (CoderResult.UNDERFLOW == r) {
+ r = encoder.flush(bBuf);
}
- if (size + buf.length > limit) {
- if (limit != LINE_LENGTH_LIMIT) {
- os.write(' ');
- }
- os.write(outBuf, 0, size);
- os.write(LINE_SEPARATOR);
- limit = LINE_LENGTH_LIMIT - 1;
- size = 0;
- }
- if (buf.length == 1) {
- outBuf[size] = buf[0];
- } else {
- System.arraycopy(buf, 0, outBuf, size, buf.length);
- }
- size += buf.length;
- }
- if (size > 0) {
- if (limit != LINE_LENGTH_LIMIT) {
- os.write(' ');
- }
- os.write(outBuf, 0, size);
+ os.write(bBuf.array(), bBuf.arrayOffset(), bBuf.position());
os.write(LINE_SEPARATOR);
+ if (CoderResult.UNDERFLOW == r) {
+ break;
+ }
+ os.write(' ');
+ bBuf.clear().limit(LINE_LENGTH_LIMIT - 1);
}
}
}
diff --git a/libcore/archive/src/main/java/java/util/jar/Pack200.java b/libcore/archive/src/main/java/java/util/jar/Pack200.java
index e0689e0..8145fa1 100644
--- a/libcore/archive/src/main/java/java/util/jar/Pack200.java
+++ b/libcore/archive/src/main/java/java/util/jar/Pack200.java
@@ -27,8 +27,6 @@
/**
* Class factory for {@link Pack200.Packer} and {@link Pack200.Unpacker}.
- *
- * @since Android 1.0
*/
public abstract class Pack200 {
@@ -39,8 +37,8 @@
/**
* Prevent this class from being instantiated.
*/
- private Pack200(){
- //do nothing
+ private Pack200() {
+ // do nothing
}
/**
@@ -50,10 +48,8 @@
* {@code 'java.util.jar.Pack200.Packer'}. If this system property is
* defined an instance of the specified class is returned, otherwise the
* system's default implementation is returned.
- * </p>
*
* @return an instance of {@code Packer}
- * @since Android 1.0
*/
public static Pack200.Packer newPacker() {
return (Packer) AccessController
@@ -82,10 +78,8 @@
* property {@code 'java.util.jar.Pack200.Unpacker'}. If this system
* property is defined an instance of the specified class is returned,
* otherwise the system's default implementation is returned.
- * </p>
*
* @return a instance of {@code Unpacker}.
- * @since Android 1.0
*/
public static Pack200.Unpacker newUnpacker() {
return (Unpacker) AccessController
@@ -107,150 +101,109 @@
/**
* The interface defining the API for converting a JAR file to an output
* stream in the Pack200 format.
- *
- * @since Android 1.0
*/
public static interface Packer {
/**
* the format of a class attribute name.
- *
- * @since Android 1.0
*/
static final String CLASS_ATTRIBUTE_PFX = "pack.class.attribute."; //$NON-NLS-1$
/**
* the format of a code attribute name.
- *
- * @since Android 1.0
*/
static final String CODE_ATTRIBUTE_PFX = "pack.code.attribute."; //$NON-NLS-1$
/**
* the deflation hint to set in the output archive.
- *
- * @since Android 1.0
*/
static final String DEFLATE_HINT = "pack.deflate.hint";//$NON-NLS-1$
/**
* the indicated amount of effort to use in compressing the archive.
- *
- * @since Android 1.0
*/
static final String EFFORT = "pack.effort";//$NON-NLS-1$
/**
* a String representation for {@code error}.
- *
- * @since Android 1.0
*/
static final String ERROR = "error";//$NON-NLS-1$
/**
* a String representation of {@code false}.
- *
- * @since Android 1.0
*/
static final String FALSE = "false";//$NON-NLS-1$
/**
* the format of a field attribute name.
- *
- * @since Android 1.0
*/
static final String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";//$NON-NLS-1$
/**
* a String representation for {@code keep}.
- *
- * @since Android 1.0
*/
static final String KEEP = "keep";//$NON-NLS-1$
/**
* decide if all elements shall transmit in their original order.
- *
- * @since Android 1.0
*/
static final String KEEP_FILE_ORDER = "pack.keep.file.order";//$NON-NLS-1$
/**
* a String representation for {@code latest}.
- *
- * @since Android 1.0
*/
static final String LATEST = "latest";//$NON-NLS-1$
/**
* the format of a method attribute name.
- *
- * @since Android 1.0
*/
static final String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";//$NON-NLS-1$
/**
* if it shall attempt to determine the latest modification time if this
* is set to {@code LATEST}.
- *
- * @since Android 1.0
*/
static final String MODIFICATION_TIME = "pack.modification.time";//$NON-NLS-1$
/**
* a String representation of {@code pass}.
- *
- * @since Android 1.0
*/
static final String PASS = "pass";//$NON-NLS-1$
/**
* the file that will not be compressed.
- *
- * @since Android 1.0
*/
static final String PASS_FILE_PFX = "pack.pass.file.";//$NON-NLS-1$
/**
* packer progress as a percentage.
- *
- * @since Android 1.0
*/
static final String PROGRESS = "pack.progress";//$NON-NLS-1$
/**
* The number of bytes of each archive segment.
- *
- * @since Android 1.0
*/
static final String SEGMENT_LIMIT = "pack.segment.limit";//$NON-NLS-1$
/**
* a String representation of {@code strip}.
- *
- * @since Android 1.0
*/
static final String STRIP = "strip";//$NON-NLS-1$
/**
* a String representation of {@code true}.
- *
- * @since Android 1.0
*/
static final String TRUE = "true";//$NON-NLS-1$
/**
* the action to take if an unknown attribute is encountered.
- *
- * @since Android 1.0
*/
static final String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";//$NON-NLS-1$
/**
* Returns a sorted map of the properties of this packer.
- *
+ *
* @return the properties of the packer.
- * @since Android 1.0
*/
SortedMap<String, String> properties();
@@ -263,7 +216,6 @@
* stream of compressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void pack(JarFile in, OutputStream out) throws IOException;
@@ -277,7 +229,6 @@
* stream of compressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void pack(JarInputStream in, OutputStream out) throws IOException;
@@ -301,52 +252,39 @@
/**
* The interface defining the API for converting a packed stream in the
* Pack200 format to a JAR file.
- *
- * @since Android 1.0
*/
public static interface Unpacker {
/**
* The String indicating if the unpacker should ignore all transmitted
* values,can be replaced by either {@code true} or {@code false}.
- *
- * @since Android 1.0
*/
static final String DEFLATE_HINT = "unpack.deflate.hint";//$NON-NLS-1$
/**
* a String representation of {@code false}.
- *
- * @since Android 1.0
*/
static final String FALSE = "false";//$NON-NLS-1$
/**
* a String representation of {@code keep}.
- *
- * @since Android 1.0
*/
static final String KEEP = "keep";//$NON-NLS-1$
/**
* the progress as a {@code percentage}.
- *
- * @since Android 1.0
*/
static final String PROGRESS = "unpack.progress";//$NON-NLS-1$
/**
* a String representation of {@code true}.
- *
- * @since Android 1.0
*/
static final String TRUE = "true";//$NON-NLS-1$
/**
* Returns a sorted map of the properties of this unpacker.
- *
+ *
* @return the properties of unpacker.
- * @since Android 1.0
*/
SortedMap<String, String> properties();
@@ -359,7 +297,6 @@
* JAR output stream of uncompressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void unpack(InputStream in, JarOutputStream out) throws IOException;
@@ -373,7 +310,6 @@
* JAR output stream of uncompressed data.
* @throws IOException
* if I/O exception occurs.
- * @since Android 1.0
*/
void unpack(File in, JarOutputStream out) throws IOException;
diff --git a/libcore/archive/src/main/java/java/util/zip/Adler32.java b/libcore/archive/src/main/java/java/util/zip/Adler32.java
index 8eaa18e..a5f77d7 100644
--- a/libcore/archive/src/main/java/java/util/zip/Adler32.java
+++ b/libcore/archive/src/main/java/java/util/zip/Adler32.java
@@ -17,14 +17,12 @@
package java.util.zip;
-
/**
* The Adler-32 class is used to compute the {@code Adler32} checksum from a set
* of data. Compared to the CRC-32 algorithm it trades reliabilty for speed.
* Refer to RFC 1950 for the specification.
- *
+ *
* @see CRC32
- * @since Android 1.0
*/
public class Adler32 implements java.util.zip.Checksum {
@@ -34,7 +32,6 @@
* Returns the {@code Adler32} checksum for all input received.
*
* @return The checksum for this instance.
- * @since Android 1.0
*/
public long getValue() {
return adler;
@@ -42,8 +39,6 @@
/**
* Reset this instance to its initial checksum.
- *
- * @since Android 1.0
*/
public void reset() {
adler = 1;
@@ -55,7 +50,6 @@
*
* @param i
* the byte to update checksum with.
- * @since Android 1.0
*/
public void update(int i) {
adler = updateByteImpl(i, adler);
@@ -66,7 +60,6 @@
*
* @param buf
* bytes to update checksum with.
- * @since Android 1.0
*/
public void update(byte[] buf) {
update(buf, 0, buf.length);
@@ -85,7 +78,6 @@
* @throws ArrayIndexOutOfBoundsException
* if {@code offset > buf.length} or {@code nbytes} is negative
* or {@code offset + nbytes > buf.length}.
- * @since Android 1.0
*/
public void update(byte[] buf, int off, int nbytes) {
// avoid int overflow, check null buf
diff --git a/libcore/archive/src/main/java/java/util/zip/CRC32.java b/libcore/archive/src/main/java/java/util/zip/CRC32.java
index 36dc376..59e8f81 100644
--- a/libcore/archive/src/main/java/java/util/zip/CRC32.java
+++ b/libcore/archive/src/main/java/java/util/zip/CRC32.java
@@ -17,12 +17,9 @@
package java.util.zip;
-
/**
* The CRC32 class is used to compute a CRC32 checksum from data provided as
* input value.
- *
- * @since Android 1.0
*/
public class CRC32 implements java.util.zip.Checksum {
@@ -34,7 +31,6 @@
* Returns the CRC32 checksum for all input received.
*
* @return The checksum for this instance.
- * @since Android 1.0
*/
public long getValue() {
return crc;
@@ -42,8 +38,6 @@
/**
* Resets the CRC32 checksum to it initial state.
- *
- * @since Android 1.0
*/
public void reset() {
tbytes = crc = 0;
@@ -52,10 +46,9 @@
/**
* Updates this checksum with the byte value provided as integer.
- *
+ *
* @param val
* represents the byte to update the checksum.
- * @since Android 1.0
*/
public void update(int val) {
crc = updateByteImpl((byte) val, crc);
@@ -66,7 +59,6 @@
*
* @param buf
* the buffer holding the data to update the checksum with.
- * @since Android 1.0
*/
public void update(byte[] buf) {
update(buf, 0, buf.length);
@@ -82,7 +74,6 @@
* the offset in {@code buf} to obtain data from.
* @param nbytes
* the number of bytes to read from {@code buf}.
- * @since Android 1.0
*/
public void update(byte[] buf, int off, int nbytes) {
// avoid int overflow, check null buf
diff --git a/libcore/archive/src/main/java/java/util/zip/CheckedInputStream.java b/libcore/archive/src/main/java/java/util/zip/CheckedInputStream.java
index 659125a..6513e66 100644
--- a/libcore/archive/src/main/java/java/util/zip/CheckedInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/CheckedInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.IOException;
import java.io.InputStream;
@@ -26,8 +25,6 @@
* same time as the data, on which the checksum is computed, is read from a
* stream. The purpose of this checksum is to establish data integrity,
* comparing the computed checksum against a published checksum value.
- *
- * @since Android 1.0
*/
public class CheckedInputStream extends java.io.FilterInputStream {
@@ -42,7 +39,6 @@
* the input stream to calculate checksum from.
* @param csum
* an entity implementing the checksum algorithm.
- * @since Android 1.0
*/
public CheckedInputStream(InputStream is, Checksum csum) {
super(is);
@@ -57,7 +53,6 @@
* otherwise.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public int read() throws IOException {
@@ -84,7 +79,6 @@
* end of the filtered stream while reading the data.
* @throws IOException
* if this stream is closed or some I/O error occurs.
- * @since Android 1.0
*/
@Override
public int read(byte[] buf, int off, int nbytes) throws IOException {
@@ -99,7 +93,6 @@
* Returns the checksum calculated on the stream read so far.
*
* @return the updated checksum.
- * @since Android 1.0
*/
public Checksum getChecksum() {
return check;
@@ -114,7 +107,6 @@
* @throws IOException
* if this stream is closed or another I/O error occurs.
* @return the number of bytes skipped.
- * @since Android 1.0
*/
@Override
public long skip(long nbytes) throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/zip/CheckedOutputStream.java b/libcore/archive/src/main/java/java/util/zip/CheckedOutputStream.java
index 9699492..08fe799 100644
--- a/libcore/archive/src/main/java/java/util/zip/CheckedOutputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/CheckedOutputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.IOException;
import java.io.OutputStream;
@@ -26,8 +25,6 @@
* of all data written to a stream. The purpose of this checksum is to establish
* data integrity, by publishing the checksum to other parties wanting to read
* the non corrupted data.
- *
- * @since Android 1.0
*/
public class CheckedOutputStream extends java.io.FilterOutputStream {
@@ -42,7 +39,6 @@
* the output stream to calculate checksum for.
* @param cs
* an entity implementing the checksum algorithm.
- * @since Android 1.0
*/
public CheckedOutputStream(OutputStream os, Checksum cs) {
super(os);
@@ -53,7 +49,6 @@
* Returns the checksum calculated on the stream read so far.
*
* @return the updated checksum.
- * @since Android 1.0
*/
public Checksum getChecksum() {
return check;
@@ -67,7 +62,6 @@
* the data value to written to the output stream.
* @throws IOException
* if an IO error has occurred.
- * @since Android 1.0
*/
@Override
public void write(int val) throws IOException {
@@ -88,7 +82,6 @@
* number of bytes to write to the output stream.
* @throws IOException
* if an IO error has occurred.
- * @since Android 1.0
*/
@Override
public void write(byte[] buf, int off, int nbytes) throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/zip/Checksum.java b/libcore/archive/src/main/java/java/util/zip/Checksum.java
index 0405c08..901ff7a 100644
--- a/libcore/archive/src/main/java/java/util/zip/Checksum.java
+++ b/libcore/archive/src/main/java/java/util/zip/Checksum.java
@@ -20,8 +20,6 @@
/**
* Holds information about a checksum which was computed with the methods
* implementing a checksum algorithm.
- *
- * @since Android 1.0
*/
public interface Checksum {
@@ -29,37 +27,32 @@
* Returns the current calculated checksum value.
*
* @return the checksum.
- * @since Android 1.0
*/
public long getValue();
/**
* Resets the checksum value applied before beginning calculations on a new
* stream of data.
- *
- * @since Android 1.0
*/
public void reset();
/**
- * Updates the checksum value with the given byte.
- *
- * @param val
- * the byte to update the checksum with.
- * @since Android 1.0
- */
- public void update(int val);
-
- /**
* Updates the checksum with the given bytes.
- *
+ *
* @param buf
* the byte array from which to read the bytes.
* @param off
* the initial position in {@code buf} to read the bytes from.
* @param nbytes
* the number of bytes to read from {@code buf}.
- * @since Android 1.0
*/
public void update(byte[] buf, int off, int nbytes);
+
+ /**
+ * Updates the checksum value with the given byte.
+ *
+ * @param val
+ * the byte to update the checksum with.
+ */
+ public void update(int val);
}
diff --git a/libcore/archive/src/main/java/java/util/zip/DataFormatException.java b/libcore/archive/src/main/java/java/util/zip/DataFormatException.java
index 9ffe2ab..1e9c5a2 100644
--- a/libcore/archive/src/main/java/java/util/zip/DataFormatException.java
+++ b/libcore/archive/src/main/java/java/util/zip/DataFormatException.java
@@ -20,8 +20,6 @@
/**
* {@code DataFormatException} is used to indicate an error in the format of a
* particular data stream which is to be uncompressed.
- *
- * @since Android 1.0
*/
public class DataFormatException extends Exception {
@@ -29,8 +27,6 @@
/**
* Constructs a new {@code DataFormatException} instance.
- *
- * @since Android 1.0
*/
public DataFormatException() {
super();
@@ -39,10 +35,9 @@
/**
* Constructs a new {@code DataFormatException} instance with the specified
* message.
- *
+ *
* @param detailMessage
* the detail message for the exception.
- * @since Android 1.0
*/
public DataFormatException(String detailMessage) {
super(detailMessage);
diff --git a/libcore/archive/src/main/java/java/util/zip/Deflater.java b/libcore/archive/src/main/java/java/util/zip/Deflater.java
index f91f1ca..38771a8 100644
--- a/libcore/archive/src/main/java/java/util/zip/Deflater.java
+++ b/libcore/archive/src/main/java/java/util/zip/Deflater.java
@@ -17,6 +17,10 @@
package java.util.zip;
+// BEGIN android-changed
+// import org.apache.harmony.luni.platform.OSResourcesMonitor;
+// END android-changed
+
/**
* This class compresses data using the <i>DEFLATE</i> algorithm (see <a
* href="http://www.gzip.org/algorithm.txt">specification</a>).
@@ -24,83 +28,65 @@
* Basically this class is part of the API to the stream based ZLIB compression
* library and is used as such by {@code DeflaterOutputStream} and its
* descendants.
- * </p>
* <p>
* The typical usage of a {@code Deflater} instance outside this package
* consists of a specific call to one of its constructors before being passed to
* an instance of {@code DeflaterOutputStream}.
- * </p>
- *
+ *
* @see DeflaterOutputStream
* @see Inflater
- * @since Android 1.0
*/
public class Deflater {
/**
* Upper bound for the compression level range.
- *
- * @since Android 1.0
*/
public static final int BEST_COMPRESSION = 9;
/**
* Lower bound for compression level range.
- *
- * @since Android 1.0
*/
public static final int BEST_SPEED = 1;
-
+
/**
* Usage of the default compression level.
- *
- * @since Android 1.0
*/
public static final int DEFAULT_COMPRESSION = -1;
-
+
/**
* Default value for compression strategy.
- *
- * @since Android 1.0
*/
public static final int DEFAULT_STRATEGY = 0;
-
+
/**
* Default value for compression method.
- *
- * @since Android 1.0
*/
public static final int DEFLATED = 8;
-
+
/**
* Possible value for compression strategy.
- *
- * @since Android 1.0
*/
public static final int FILTERED = 1;
-
+
/**
* Possible value for compression strategy.
- *
- * @since Android 1.0
*/
public static final int HUFFMAN_ONLY = 2;
-
+
/**
* Possible value for compression level.
- *
- * @since Android 1.0
*/
public static final int NO_COMPRESSION = 0;
private static final int Z_NO_FLUSH = 0;
private static final int Z_FINISH = 4;
-
+
// Fill in the JNI id caches
private static native void oneTimeInitialization();
-
- // A stub buffer used when deflate() called while inputBuffer has not been set.
+
+ // A stub buffer used when deflate() called while inputBuffer has not been
+ // set.
private static final byte[] STUB_INPUT_BUFFER = new byte[0];
static {
@@ -120,21 +106,19 @@
private byte[] inputBuffer;
private int inRead;
-
+
private int inLength;
-
+
/**
* Constructs a new {@code Deflater} instance with default compression
* level. The strategy can be specified with {@link #setStrategy}, only. A
* header is added to the output by default; use constructor {@code
* Deflater(level, boolean)} if you need to omit the header.
- *
- * @since Android 1.0
*/
public Deflater() {
this(DEFAULT_COMPRESSION, false);
}
-
+
/**
* Constructs a new {@code Deflater} instance with a specific compression
* level. The strategy can be specified with {@code setStrategy}, only. A
@@ -143,7 +127,6 @@
*
* @param level
* the compression level in the range between 0 and 9.
- * @since Android 1.0
*/
public Deflater(int level) {
this(level, false);
@@ -159,7 +142,6 @@
* the compression level in the range between 0 and 9.
* @param noHeader
* {@code true} indicates that no ZLIB header should be written.
- * @since Android 1.0
*/
public Deflater(int level, boolean noHeader) {
super();
@@ -167,7 +149,8 @@
throw new IllegalArgumentException();
}
compressLevel = level;
- streamHandle = createStream(compressLevel, strategy, noHeader);
+ streamHandle = createStreamWithMemoryEnsurance(compressLevel, strategy,
+ noHeader);
}
/**
@@ -178,7 +161,6 @@
* buffer to write compressed data to.
* @return number of bytes of compressed data written to {@code buf}.
* @see #deflate(byte[], int, int)
- * @since Android 1.0
*/
public int deflate(byte[] buf) {
return deflate(buf, 0, buf.length);
@@ -195,7 +177,6 @@
* @param nbytes
* maximum number of bytes of compressed data to be written.
* @return the number of bytes of compressed data written to {@code buf}.
- * @since Android 1.0
*/
public synchronized int deflate(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -224,8 +205,6 @@
* finalize()}, it can be called explicitly in order to free native
* resources before the next GC cycle. After {@code end()} was called other
* methods will typically throw an {@code IllegalStateException}.
- *
- * @since Android 1.0
*/
public synchronized void end() {
if (streamHandle != -1) {
@@ -245,7 +224,6 @@
* to it.
*
* @see #finished
- * @since Android 1.0
*/
public synchronized void finish() {
flushParm = Z_FINISH;
@@ -256,7 +234,6 @@
* compressed.
*
* @return true if all data has been compressed, false otherwise.
- * @since Android 1.0
*/
public synchronized boolean finished() {
return finished;
@@ -271,7 +248,6 @@
* used.
* @see #setDictionary(byte[])
* @see #setDictionary(byte[], int, int)
- * @since Android 1.0
*/
public synchronized int getAdler() {
if (streamHandle == -1) {
@@ -287,14 +263,13 @@
* Returns the total number of bytes of input consumed by the {@code Deflater}.
*
* @return number of bytes of input read.
- * @since Android 1.0
*/
public synchronized int getTotalIn() {
if (streamHandle == -1) {
throw new IllegalStateException();
}
- return (int)getTotalInImpl(streamHandle);
+ return (int) getTotalInImpl(streamHandle);
}
private synchronized native long getTotalInImpl(long handle);
@@ -303,14 +278,13 @@
* Returns the total number of compressed bytes output by this {@code Deflater}.
*
* @return number of compressed bytes output.
- * @since Android 1.0
*/
public synchronized int getTotalOut() {
if (streamHandle == -1) {
throw new IllegalStateException();
}
- return (int)getTotalOutImpl(streamHandle);
+ return (int) getTotalOutImpl(streamHandle);
}
private synchronized native long getTotalOutImpl(long handle);
@@ -327,7 +301,6 @@
* @see #finished()
* @see #setInput(byte[])
* @see #setInput(byte[], int, int)
- * @since Android 1.0
*/
public synchronized boolean needsInput() {
if (inputBuffer == null) {
@@ -343,7 +316,6 @@
* {@code true} if the {@code Deflater} is to be reused.
*
* @see #finished
- * @since Android 1.0
*/
public synchronized void reset() {
if (streamHandle == -1) {
@@ -367,7 +339,6 @@
* @param buf
* the buffer containing the dictionary data bytes.
* @see Deflater#Deflater(int, boolean)
- * @since Android 1.0
*/
public void setDictionary(byte[] buf) {
setDictionary(buf, 0, buf.length);
@@ -378,7 +349,7 @@
* setDictionary() can only be called if this {@code Deflater} supports the writing
* of ZLIB headers. This is the default behaviour but can be overridden
* using {@code Deflater(int, boolean)}.
- *
+ *
* @param buf
* the buffer containing the dictionary data bytes.
* @param off
@@ -386,7 +357,6 @@
* @param nbytes
* the length of the data.
* @see Deflater#Deflater(int, boolean)
- * @since Android 1.0
*/
public synchronized void setDictionary(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -410,7 +380,6 @@
*
* @param buf
* the buffer.
- * @since Android 1.0
*/
public void setInput(byte[] buf) {
setInput(buf, 0, buf.length);
@@ -427,7 +396,6 @@
* the offset of the data.
* @param nbytes
* the length of the data.
- * @since Android 1.0
*/
public synchronized void setInput(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -463,7 +431,6 @@
* compression level to use
* @exception IllegalArgumentException
* If the compression level is invalid.
- * @since Android 1.0
*/
public synchronized void setLevel(int level) {
if (level < DEFAULT_COMPRESSION || level > BEST_COMPRESSION) {
@@ -485,7 +452,6 @@
* @exception IllegalArgumentException
* If the strategy specified is not one of FILTERED,
* HUFFMAN_ONLY or DEFAULT_STRATEGY.
- * @since Android 1.0
*/
public synchronized void setStrategy(int strategy) {
if (strategy < DEFAULT_STRATEGY || strategy > HUFFMAN_ONLY) {
@@ -496,14 +462,14 @@
}
this.strategy = strategy;
}
-
+
/**
* Returns a long int of total number of bytes read by the {@code Deflater}. This
* method performs the same as {@code getTotalIn} except it returns a long value
* instead of an integer
*
+ * @see #getTotalIn()
* @return total number of bytes read by {@code Deflater}.
- * @since Android 1.0
*/
public synchronized long getBytesRead() {
// Throw NPE here
@@ -518,8 +484,8 @@
* method performs the same as {@code getTotalOut} except it returns a long
* value instead of an integer
*
+ * @see #getTotalOut()
* @return bytes exactly write by {@code Deflater}
- * @since Android 1.0
*/
public synchronized long getBytesWritten() {
// Throw NPE here
@@ -529,5 +495,13 @@
return getTotalOutImpl(streamHandle);
}
+ private long createStreamWithMemoryEnsurance(int level, int strategy1,
+ boolean noHeader1) {
+ // BEGIN android-changed
+ // OSResourcesMonitor.ensurePhysicalMemoryCapacity();
+ // END android-changed
+ return createStream(level, strategy1, noHeader1);
+ }
+
private native long createStream(int level, int strategy1, boolean noHeader1);
}
diff --git a/libcore/archive/src/main/java/java/util/zip/DeflaterOutputStream.java b/libcore/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
index 773e4c4..03769fb 100644
--- a/libcore/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/DeflaterOutputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -28,24 +27,19 @@
* This class provides an implementation of {@code FilterOutputStream} that
* compresses data using the <i>DEFLATE</i> algorithm. Basically it wraps the
* {@code Deflater} class and takes care of the buffering.
- *
+ *
* @see Deflater
- * @since Android 1.0
*/
public class DeflaterOutputStream extends FilterOutputStream {
static final int BUF_SIZE = 512;
/**
* The buffer for the data to be written to.
- *
- * @since Android 1.0
*/
protected byte[] buf;
/**
* The deflater used.
- *
- * @since Android 1.0
*/
protected Deflater def;
@@ -61,7 +55,6 @@
* @param def
* is the specific {@code Deflater} that is used to compress
* data.
- * @since Android 1.0
*/
public DeflaterOutputStream(OutputStream os, Deflater def) {
this(os, def, BUF_SIZE);
@@ -76,7 +69,6 @@
*
* @param os
* is the OutputStream where to write the compressed data to.
- * @since Android 1.0
*/
public DeflaterOutputStream(OutputStream os) {
this(os, new Deflater());
@@ -94,7 +86,6 @@
* data.
* @param bsize
* is the size to be used for the internal buffer.
- * @since Android 1.0
*/
public DeflaterOutputStream(OutputStream os, Deflater def, int bsize) {
super(os);
@@ -114,7 +105,6 @@
*
* @throws IOException
* If an error occurs during deflation.
- * @since Android 1.0
*/
protected void deflate() throws IOException {
int x = 0;
@@ -132,7 +122,6 @@
* @throws IOException
* If an error occurs while closing the data compression
* process.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -149,7 +138,6 @@
*
* @throws IOException
* If an error occurs.
- * @since Android 1.0
*/
public void finish() throws IOException {
if (done) {
@@ -186,7 +174,6 @@
* the number of bytes of data to read from the buffer.
* @throws IOException
* If an error occurs during writing.
- * @since Android 1.0
*/
@Override
public void write(byte[] buffer, int off, int nbytes) throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java b/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java
index fc70d62..bb84f5b 100644
--- a/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/GZIPInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -28,49 +27,40 @@
* The {@code GZIPInputStream} class is used to read data stored in the GZIP
* format, reading and decompressing GZIP data from the underlying stream into
* its buffer.
- *
- * @since Android 1.0
*/
-public class GZIPInputStream extends java.util.zip.InflaterInputStream {
+public class GZIPInputStream extends InflaterInputStream {
+
+ private static final int FCOMMENT = 16;
+
+ private static final int FEXTRA = 4;
+
+ private static final int FHCRC = 2;
+
+ private static final int FNAME = 8;
+
+ /**
+ * The magic header for the GZIP format.
+ */
+ public final static int GZIP_MAGIC = 0x8b1f;
/**
* The checksum algorithm used when handling uncompressed data.
- *
- * @since Android 1.0
*/
protected CRC32 crc = new CRC32();
/**
* Indicates the end of the input stream.
- *
- * @since Android 1.0
*/
protected boolean eos = false;
/**
- * The magic header for the GZIP format.
- *
- * @since Android 1.0
- */
- public final static int GZIP_MAGIC = 0x8b1f;
-
- private static final int FHCRC = 2;
-
- private static final int FEXTRA = 4;
-
- private static final int FNAME = 8;
-
- private static final int FCOMMENT = 16;
-
- /**
* Construct a {@code GZIPInputStream} to read from GZIP data from the
* underlying stream.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPInputStream(InputStream is) throws IOException {
this(is, BUF_SIZE);
@@ -86,7 +76,6 @@
* the internal read buffer size.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPInputStream(InputStream is, int size) throws IOException {
super(is, new Inflater(true), size);
@@ -134,6 +123,15 @@
}
}
+ /**
+ * Closes this stream and any underlying streams.
+ */
+ @Override
+ public void close() throws IOException {
+ eos = true;
+ super.close();
+ }
+
private long getLong(byte[] buffer, int off) {
long l = 0;
l |= (buffer[off] & 0xFF);
@@ -147,12 +145,23 @@
return (buffer[off] & 0xFF) | ((buffer[off + 1] & 0xFF) << 8);
}
+ /**
+ * Reads and decompresses GZIP data from the underlying stream into the
+ * given buffer.
+ *
+ * @param buffer
+ * Buffer to receive data
+ * @param off
+ * Offset in buffer to store data
+ * @param nbytes
+ * Number of bytes to read
+ */
@Override
public int read(byte[] buffer, int off, int nbytes) throws IOException {
if (closed) {
throw new IOException(Messages.getString("archive.1E")); //$NON-NLS-1$
}
- if(eof){
+ if (eof) {
return -1;
}
// avoid int overflow, check null buffer
@@ -164,17 +173,15 @@
} else if (!eos) {
eos = true;
// Get non-compressed bytes read by fill
- // BEGIN android-changed
- // copied from newer version of harmony
int size = inf.getRemaining();
final int trailerSize = 8; // crc (4 bytes) + total out (4
- // bytes)
+ // bytes)
byte[] b = new byte[trailerSize];
int copySize = (size > trailerSize) ? trailerSize : size;
System.arraycopy(buf, len - size, b, 0, copySize);
- readFully(b, copySize, trailerSize - copySize);
- // END android-changed
+ readFully(b, copySize, trailerSize - copySize);
+
if (getLong(b, 0) != crc.getValue()) {
throw new IOException(Messages.getString("archive.20")); //$NON-NLS-1$
}
@@ -186,12 +193,6 @@
}
throw new ArrayIndexOutOfBoundsException();
}
-
- @Override
- public void close() throws IOException {
- eos = true;
- super.close();
- }
private void readFully(byte[] buffer, int offset, int length)
throws IOException {
diff --git a/libcore/archive/src/main/java/java/util/zip/GZIPOutputStream.java b/libcore/archive/src/main/java/java/util/zip/GZIPOutputStream.java
index fa41e19..f146da1 100644
--- a/libcore/archive/src/main/java/java/util/zip/GZIPOutputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/GZIPOutputStream.java
@@ -17,22 +17,17 @@
package java.util.zip;
-
import java.io.IOException;
import java.io.OutputStream;
/**
* The {@code GZIPOutputStream} class is used to write data to a stream in the
* GZIP storage format.
- *
- * @since Android 1.0
*/
public class GZIPOutputStream extends DeflaterOutputStream {
/**
* The checksum algorithm used when treating uncompressed data.
- *
- * @since Android 1.0
*/
protected CRC32 crc = new CRC32();
@@ -44,7 +39,6 @@
* the {@code OutputStream} to write data to.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPOutputStream(OutputStream os) throws IOException {
this(os, BUF_SIZE);
@@ -61,7 +55,6 @@
* the internal buffer size.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public GZIPOutputStream(OutputStream os, int size) throws IOException {
super(os, new Deflater(Deflater.DEFAULT_COMPRESSION, true), size);
@@ -76,10 +69,9 @@
/**
* Indicates to the stream that all data has been written out, and any GZIP
* terminal data can now be written.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public void finish() throws IOException {
@@ -88,24 +80,29 @@
writeLong(crc.tbytes);
}
+ /**
+ * Write up to nbytes of data from the given buffer, starting at offset off,
+ * to the underlying stream in GZIP format.
+ */
@Override
public void write(byte[] buffer, int off, int nbytes) throws IOException {
super.write(buffer, off, nbytes);
crc.update(buffer, off, nbytes);
}
- private int writeShort(int i) throws IOException {
- out.write(i & 0xFF);
- out.write((i >> 8) & 0xFF);
+ private long writeLong(long i) throws IOException {
+ // Write out the long value as an unsigned int
+ int unsigned = (int) i;
+ out.write(unsigned & 0xFF);
+ out.write((unsigned >> 8) & 0xFF);
+ out.write((unsigned >> 16) & 0xFF);
+ out.write((unsigned >> 24) & 0xFF);
return i;
}
- private long writeLong(long i) throws IOException {
- // Write out the long value as an unsigned int
- out.write((int) (i & 0xFF));
- out.write((int) (i >> 8) & 0xFF);
- out.write((int) (i >> 16) & 0xFF);
- out.write((int) (i >> 24) & 0xFF);
+ private int writeShort(int i) throws IOException {
+ out.write(i & 0xFF);
+ out.write((i >> 8) & 0xFF);
return i;
}
}
diff --git a/libcore/archive/src/main/java/java/util/zip/Inflater.java b/libcore/archive/src/main/java/java/util/zip/Inflater.java
index 9b93e54..cb1ce68 100644
--- a/libcore/archive/src/main/java/java/util/zip/Inflater.java
+++ b/libcore/archive/src/main/java/java/util/zip/Inflater.java
@@ -30,45 +30,65 @@
* Basically this class is part of the API to the stream based ZLIB compression
* library and is used as such by {@code InflaterInputStream} and its
* descendants.
- * </p>
* <p>
* The typical usage of a {@code Inflater} outside this package consists of a
* specific call to one of its constructors before being passed to an instance
* of {@code InflaterInputStream}.
- * </p>
- *
+ *
* @see InflaterInputStream
* @see Deflater
- * @since Android 1.0
*/
public class Inflater {
- private boolean finished; // Set by the inflateImpl native
-
- private boolean needsDictionary; // Set by the inflateImpl native
-
- private long streamHandle = -1;
-
- int inRead;
-
- int inLength;
-
- // Fill in the JNI id caches
- private static native void oneTimeInitialization();
+ private static final byte MAGIC_NUMBER = 120;
static {
oneTimeInitialization();
}
-
- private static final byte MAGIC_NUMBER = 120;
+
+ // Fill in the JNI id caches
+ private static native void oneTimeInitialization();
+
+ private boolean finished; // Set by the inflateImpl native
+
private boolean gotFirstByte = false;
+
+ int inLength;
+
+ int inRead;
+
+ private boolean needsDictionary; // Set by the inflateImpl native
+
private boolean pass_magic_number_check = true;
-
+
+ private long streamHandle = -1;
+
+ /**
+ * This constructor creates an inflater that expects a header from the input
+ * stream. Use {@code Inflater(boolean)} if the input comes without a ZLIB
+ * header.
+ */
+ public Inflater() {
+ this(false);
+ }
+
+ /**
+ * This constructor allows to create an inflater that expects no header from
+ * the input stream.
+ *
+ * @param noHeader
+ * {@code true} indicates that no ZLIB header comes with the
+ * input.
+ */
+ public Inflater(boolean noHeader) {
+ streamHandle = createStream(noHeader);
+ }
+
+ private native long createStream(boolean noHeader1);
+
/**
* Release any resources associated with this {@code Inflater}. Any unused
* input/output is discarded. This is also called by the finalize method.
- *
- * @since Android 1.0
*/
public synchronized void end() {
if (streamHandle != -1) {
@@ -91,10 +111,9 @@
* stream. If deflated bytes remain and {@code needsInput()} returns {@code
* true} this method will return {@code false}. This method should be
* called after all deflated input is supplied to the {@code Inflater}.
- *
+ *
* @return {@code true} if all input has been inflated, {@code false}
* otherwise.
- * @since Android 1.0
*/
public synchronized boolean finished() {
return finished;
@@ -103,10 +122,9 @@
/**
* Returns the <i>Adler32</i> checksum of either all bytes inflated, or the
* checksum of the preset dictionary if one has been supplied.
- *
+ *
* @return The <i>Adler32</i> checksum associated with this
* {@code Inflater}.
- * @since Android 1.0 .
*/
public synchronized int getAdler() {
if (streamHandle == -1) {
@@ -118,11 +136,40 @@
private native synchronized int getAdlerImpl(long handle);
/**
+ * Returns the total number of bytes read by the {@code Inflater}. This
+ * method performs the same as {@code getTotalIn()} except that it returns a
+ * {@code long} value instead of an integer.
+ *
+ * @return the total number of bytes read.
+ */
+ public synchronized long getBytesRead() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalInImpl(streamHandle);
+ }
+
+ /**
+ * Returns a the total number of bytes read by the {@code Inflater}. This
+ * method performs the same as {@code getTotalOut} except it returns a
+ * {@code long} value instead of an integer.
+ *
+ * @return the total bytes written to the output buffer.
+ */
+ public synchronized long getBytesWritten() {
+ // Throw NPE here
+ if (streamHandle == -1) {
+ throw new NullPointerException();
+ }
+ return getTotalOutImpl(streamHandle);
+ }
+
+ /**
* Returns the number of bytes of current input remaining to be read by the
* inflater.
- *
+ *
* @return the number of bytes of unread input.
- * @since Android 1.0
*/
public synchronized int getRemaining() {
return inLength - inRead;
@@ -131,9 +178,8 @@
/**
* Returns total number of bytes of input read by the {@code Inflater}. The
* result value is limited by {@code Integer.MAX_VALUE}.
- *
+ *
* @return the total number of bytes read.
- * @since Android 1.0
*/
public synchronized int getTotalIn() {
if (streamHandle == -1) {
@@ -149,9 +195,8 @@
/**
* Returns total number of bytes written to the output buffer by the {@code
* Inflater}. The result value is limited by {@code Integer.MAX_VALUE}.
- *
+ *
* @return the total bytes of output data written.
- * @since Android 1.0
*/
public synchronized int getTotalOut() {
if (streamHandle == -1) {
@@ -166,14 +211,13 @@
/**
* Inflates bytes from current input and stores them in {@code buf}.
- *
+ *
* @param buf
* the buffer where decompressed data bytes are written.
* @return the number of bytes inflated.
* @throws DataFormatException
* if the underlying stream is corrupted or was not compressed
* using a {@code Deflater}.
- * @since Android 1.0
*/
public int inflate(byte[] buf) throws DataFormatException {
return inflate(buf, 0, buf.length);
@@ -182,7 +226,7 @@
/**
* Inflates up to n bytes from the current input and stores them in {@code
* buf} starting at {@code off}.
- *
+ *
* @param buf
* the buffer to write inflated bytes to.
* @param off
@@ -205,7 +249,7 @@
if (streamHandle == -1) {
throw new IllegalStateException();
}
-
+
if (!pass_magic_number_check) {
throw new DataFormatException();
}
@@ -213,7 +257,7 @@
if (needsInput()) {
return 0;
}
-
+
boolean neededDict = needsDictionary;
needsDictionary = false;
int result = inflateImpl(buf, off, nbytes, streamHandle);
@@ -229,41 +273,15 @@
int nbytes, long handle);
/**
- * This constructor creates an inflater that expects a header from the input
- * stream. Use {@code Inflater(boolean)} if the input comes without a ZLIB
- * header.
- *
- * @since Android 1.0
- * @since Android 1.0
- */
- public Inflater() {
- this(false);
- }
-
- /**
- * This constructor allows to create an inflater that expects no header from
- * the input stream.
- *
- * @param noHeader
- * {@code true} indicates that no ZLIB header comes with the
- * input.
- * @since Android 1.0
- */
- public Inflater(boolean noHeader) {
- streamHandle = createStream(noHeader);
- }
-
- /**
* Indicates whether the input bytes were compressed with a preset
* dictionary. This method should be called prior to {@code inflate()} to
* determine whether a dictionary is required. If so {@code setDictionary()}
* should be called with the appropriate dictionary prior to calling {@code
* inflate()}.
- *
+ *
* @return {@code true} if a preset dictionary is required for inflation.
* @see #setDictionary(byte[])
* @see #setDictionary(byte[], int, int)
- * @since Android 1.0
*/
public synchronized boolean needsDictionary() {
return needsDictionary;
@@ -271,11 +289,10 @@
/**
* Indicates that input has to be passed to the inflater.
- *
+ *
* @return {@code true} if {@code setInput} has to be called before
* inflation can proceed.
* @see #setInput(byte[])
- * @since Android 1.0
*/
public synchronized boolean needsInput() {
return inRead == inLength;
@@ -284,8 +301,6 @@
/**
* Resets the {@code Inflater}. Should be called prior to inflating a new
* set of data.
- *
- * @since Android 1.0
*/
public synchronized void reset() {
if (streamHandle == -1) {
@@ -303,11 +318,10 @@
* Sets the preset dictionary to be used for inflation to {@code buf}.
* {@code needsDictionary()} can be called to determine whether the current
* input was deflated using a preset dictionary.
- *
+ *
* @param buf
* The buffer containing the dictionary bytes.
* @see #needsDictionary
- * @since Android 1.0
*/
public synchronized void setDictionary(byte[] buf) {
setDictionary(buf, 0, buf.length);
@@ -316,7 +330,11 @@
/**
* Like {@code setDictionary(byte[])}, allowing to define a specific region
* inside {@code buf} to be used as a dictionary.
- *
+ * <p>
+ * The dictionary should be set if the {@link #inflate(byte[])} returned
+ * zero bytes inflated and {@link #needsDictionary()} returns
+ * <code>true</code>.
+ *
* @param buf
* the buffer containing the dictionary data bytes.
* @param off
@@ -324,7 +342,6 @@
* @param nbytes
* the length of the data.
* @see #needsDictionary
- * @since Android 1.0
*/
public synchronized void setDictionary(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -345,11 +362,10 @@
/**
* Sets the current input to to be decrompressed. This method should only be
* called if {@code needsInput()} returns {@code true}.
- *
+ *
* @param buf
* the input buffer.
* @see #needsInput
- * @since Android 1.0
*/
public synchronized void setInput(byte[] buf) {
setInput(buf, 0, buf.length);
@@ -360,7 +376,7 @@
* {@code off} and ending at {@code nbytes - 1} where data is written after
* decompression. This method should only be called if {@code needsInput()}
* returns {@code true}.
- *
+ *
* @param buf
* the input buffer.
* @param off
@@ -368,7 +384,6 @@
* @param nbytes
* the number of bytes to read.
* @see #needsInput
- * @since Android 1.0
*/
public synchronized void setInput(byte[] buf, int off, int nbytes) {
if (streamHandle == -1) {
@@ -394,10 +409,9 @@
// And at a first glance it doesn't look like the first byte has
// to be 120.
// END android-note
- if(!gotFirstByte && nbytes>0)
- {
- pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
- gotFirstByte = true;
+ if (!gotFirstByte && nbytes > 0) {
+ pass_magic_number_check = (buf[off] == MAGIC_NUMBER || nbytes > 1);
+ gotFirstByte = true;
}
}
@@ -407,14 +421,13 @@
* off} and ending at {@code nbytes - 1}. This method should only be called
* if {@code needsInput()} returns {@code true}.
*
- * @param file
+ * @param fd
* the input file.
* @param off
* the offset to read from in buffer.
* @param nbytes
* the number of bytes to read.
* @see #needsInput
- * @since Android 1.0
*/
synchronized int setFileInput(FileDescriptor fd, long off, int nbytes) {
if (streamHandle == -1) {
@@ -426,38 +439,6 @@
}
// END android-added
- /**
- * Returns the total number of bytes read by the {@code Inflater}. This
- * method performs the same as {@code getTotalIn()} except that it returns a
- * {@code long} value instead of an integer.
- *
- * @return the total number of bytes read.
- * @since Android 1.0
- */
- public synchronized long getBytesRead() {
- // Throw NPE here
- if (streamHandle == -1) {
- throw new NullPointerException();
- }
- return getTotalInImpl(streamHandle);
- }
-
- /**
- * Returns a the total number of bytes read by the {@code Inflater}. This
- * method performs the same as {@code getTotalOut} except it returns a
- * {@code long} value instead of an integer.
- *
- * @return the total bytes written to the output buffer.
- * @since Android 1.0
- */
- public synchronized long getBytesWritten() {
- // Throw NPE here
- if (streamHandle == -1) {
- throw new NullPointerException();
- }
- return getTotalOutImpl(streamHandle);
- }
-
private native synchronized void setInputImpl(byte[] buf, int off,
int nbytes, long handle);
@@ -465,6 +446,4 @@
private native synchronized int setFileInputImpl(FileDescriptor fd, long off,
int nbytes, long handle);
// END android-added
-
- private native long createStream(boolean noHeader1);
}
diff --git a/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java b/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java
index 5d3bda0..1fd3602 100644
--- a/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/InflaterInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.EOFException;
import java.io.FilterInputStream;
import java.io.IOException;
@@ -31,31 +30,24 @@
* (see <a href="http://www.gzip.org/algorithm.txt">specification</a>).
* Basically it wraps the {@code Inflater} class and takes care of the
* buffering.
- *
+ *
* @see Inflater
* @see DeflaterOutputStream
- * @since Android 1.0
*/
public class InflaterInputStream extends FilterInputStream {
/**
* The inflater used for this stream.
- *
- * @since Android 1.0
*/
protected Inflater inf;
/**
* The input buffer used for decompression.
- *
- * @since Android 1.0
*/
protected byte[] buf;
/**
* The length of the buffer.
- *
- * @since Android 1.0
*/
protected int len;
@@ -74,10 +66,9 @@
* InputStream} from which the compressed data is to be read from. Default
* settings for the {@code Inflater} and internal buffer are be used. In
* particular the Inflater expects a ZLIB header from the input stream.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
- * @since Android 1.0
*/
public InflaterInputStream(InputStream is) {
this(is, new Inflater(), BUF_SIZE);
@@ -86,12 +77,11 @@
/**
* This constructor lets you pass a specifically initialized Inflater,
* for example one that expects no ZLIB header.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
* @param inf
* the specific {@code Inflater} for uncompressing data.
- * @since Android 1.0
*/
public InflaterInputStream(InputStream is, Inflater inf) {
this(is, inf, BUF_SIZE);
@@ -100,14 +90,13 @@
/**
* This constructor lets you specify both the {@code Inflater} as well as
* the internal buffer size to be used.
- *
+ *
* @param is
* the {@code InputStream} to read data from.
* @param inf
* the specific {@code Inflater} for uncompressing data.
* @param bsize
* the size to be used for the internal buffer.
- * @since Android 1.0
*/
public InflaterInputStream(InputStream is, Inflater inf, int bsize) {
super(is);
@@ -129,11 +118,10 @@
/**
* Reads a single byte of decompressed data.
- *
+ *
* @return the byte read.
* @throws IOException
* if an error occurs reading the byte.
- * @since Android 1.0
*/
@Override
public int read() throws IOException {
@@ -147,7 +135,7 @@
/**
* Reads up to {@code nbytes} of decompressed data and stores it in
* {@code buffer} starting at {@code off}.
- *
+ *
* @param buffer
* the buffer to write data to.
* @param off
@@ -157,7 +145,6 @@
* @return Number of uncompressed bytes read
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
@Override
public int read(byte[] buffer, int off, int nbytes) throws IOException {
@@ -197,7 +184,7 @@
if (len == -1) {
throw new EOFException();
}
- throw (IOException)(new IOException().initCause(e));
+ throw (IOException) (new IOException().initCause(e));
}
if (result > 0) {
return result;
@@ -208,20 +195,18 @@
return -1;
} else if (len == -1) {
throw new EOFException();
- // If result == 0, fill() and try again
+ // If result == 0, fill() and try again
}
} while (true);
}
throw new ArrayIndexOutOfBoundsException();
}
-
/**
* Fills the input buffer with data to be decompressed.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
protected void fill() throws IOException {
if (closed) {
@@ -246,17 +231,21 @@
/**
* Skips up to n bytes of uncompressed data.
- *
+ *
* @param nbytes
* the number of bytes to skip.
* @return the number of uncompressed bytes skipped.
* @throws IOException
* if an error occurs skipping.
- * @since Android 1.0
*/
@Override
public long skip(long nbytes) throws IOException {
if (nbytes >= 0) {
+ // BEGIN android-changed
+ if (buf == null) {
+ buf = new byte[BUF_SIZE];
+ }
+ // END android-changed
long count = 0, rem = 0;
while (count < nbytes) {
int x = read(buf, 0,
@@ -275,11 +264,10 @@
/**
* Returns whether data can be read from this stream.
- *
+ *
* @return 0 if this stream has been closed, 1 otherwise.
* @throws IOException
* If an error occurs.
- * @since Android 1.0
*/
@Override
public int available() throws IOException {
@@ -295,10 +283,9 @@
/**
* Closes the input stream.
- *
+ *
* @throws IOException
* If an error occurs closing the input stream.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -309,17 +296,15 @@
super.close();
}
}
-
+
/**
- * This implementation overrides the super type implementation to do nothing
- * at all.
- *
+ * Marks the current position in the stream. This implementation overrides
+ * the super type implementation to do nothing at all.
+ *
* @param readlimit
* of no use.
- * @since Android 1.0
*/
@Override
- @SuppressWarnings("unused")
public void mark(int readlimit) {
// do nothing
}
@@ -328,22 +313,20 @@
* Reset the position of the stream to the last marked position. This
* implementation overrides the supertype implementation and always throws
* an {@link IOException IOException} when called.
- *
+ *
* @throws IOException
* if the method is called
- * @since Android 1.0
*/
@Override
- public void reset() throws IOException{
+ public void reset() throws IOException {
throw new IOException();
}
-
+
/**
* Returns whether the receiver implements {@code mark} semantics. This type
* does not support {@code mark()}, so always responds {@code false}.
- *
+ *
* @return false, always
- * @since Android 1.0
*/
@Override
public boolean markSupported() {
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipConstants.java b/libcore/archive/src/main/java/java/util/zip/ZipConstants.java
index d804b0e..d00adc9 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipConstants.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipConstants.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
interface ZipConstants {
public static final long LOCSIG = 0x4034b50, EXTSIG = 0x8074b50,
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipEntry.java b/libcore/archive/src/main/java/java/util/zip/ZipEntry.java
index 2cc7a9c..9774b6a 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipEntry.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipEntry.java
@@ -36,10 +36,9 @@
* itself. For example when reading a <i>ZIP-file</i> you will first retrieve
* all its entries in a collection and then read the data for a specific entry
* through an input stream.
- *
+ *
* @see ZipFile
* @see ZipOutputStream
- * @since Android 1.0
*/
public class ZipEntry implements ZipConstants, Cloneable {
String name, comment;
@@ -94,26 +93,21 @@
/**
* Zip entry state: Deflated.
- *
- * @since Android 1.0
*/
public static final int DEFLATED = 8;
/**
* Zip entry state: Stored.
- *
- * @since Android 1.0
*/
public static final int STORED = 0;
/**
* Constructs a new {@code ZipEntry} with the specified name.
- *
+ *
* @param name
* the name of the ZIP entry.
* @throws IllegalArgumentException
* if the name length is outside the range (> 0xFFFF).
- * @since Android 1.0
*/
public ZipEntry(String name) {
if (name == null) {
@@ -147,11 +141,10 @@
/**
* Gets the comment for this {@code ZipEntry}.
- *
+ *
* @return the comment for this {@code ZipEntry}, or {@code null} if there
* is no comment. If we're reading an archive with
* {@code ZipInputStream} the comment is not available.
- * @since Android 1.0
*/
public String getComment() {
return comment;
@@ -159,10 +152,9 @@
/**
* Gets the compressed size of this {@code ZipEntry}.
- *
+ *
* @return the compressed size, or -1 if the compressed size has not been
* set.
- * @since Android 1.0
*/
public long getCompressedSize() {
return compressedSize;
@@ -170,9 +162,8 @@
/**
* Gets the checksum for this {@code ZipEntry}.
- *
+ *
* @return the checksum, or -1 if the checksum has not been set.
- * @since Android 1.0
*/
public long getCrc() {
return crc;
@@ -180,10 +171,9 @@
/**
* Gets the extra information for this {@code ZipEntry}.
- *
+ *
* @return a byte array containing the extra information, or {@code null} if
* there is none.
- * @since Android 1.0
*/
public byte[] getExtra() {
return extra;
@@ -191,10 +181,9 @@
/**
* Gets the compression method for this {@code ZipEntry}.
- *
+ *
* @return the compression method, either {@code DEFLATED}, {@code STORED}
* or -1 if the compression method has not been set.
- * @since Android 1.0
*/
public int getMethod() {
return compressionMethod;
@@ -202,9 +191,8 @@
/**
* Gets the name of this {@code ZipEntry}.
- *
+ *
* @return the entry name.
- * @since Android 1.0
*/
public String getName() {
return name;
@@ -212,10 +200,9 @@
/**
* Gets the uncompressed size of this {@code ZipEntry}.
- *
+ *
* @return the uncompressed size, or {@code -1} if the size has not been
* set.
- * @since Android 1.0
*/
public long getSize() {
return size;
@@ -223,10 +210,9 @@
/**
* Gets the last modification time of this {@code ZipEntry}.
- *
+ *
* @return the last modification time as the number of milliseconds since
* Jan. 1, 1970.
- * @since Android 1.0
*/
public long getTime() {
if (time != -1) {
@@ -242,10 +228,9 @@
/**
* Determine whether or not this {@code ZipEntry} is a directory.
- *
+ *
* @return {@code true} when this {@code ZipEntry} is a directory, {@code
* false} otherwise.
- * @since Android 1.0
*/
public boolean isDirectory() {
return name.charAt(name.length() - 1) == '/';
@@ -253,10 +238,9 @@
/**
* Sets the comment for this {@code ZipEntry}.
- *
+ *
* @param string
* the comment for this entry.
- * @since Android 1.0
*/
public void setComment(String string) {
if (string == null || string.length() <= 0xFFFF) {
@@ -268,10 +252,9 @@
/**
* Sets the compressed size for this {@code ZipEntry}.
- *
+ *
* @param value
* the compressed size (in bytes).
- * @since Android 1.0
*/
public void setCompressedSize(long value) {
compressedSize = value;
@@ -279,12 +262,11 @@
/**
* Sets the checksum for this {@code ZipEntry}.
- *
+ *
* @param value
* the checksum for this entry.
* @throws IllegalArgumentException
* if {@code value} is < 0 or > 0xFFFFFFFFL.
- * @since Android 1.0
*/
public void setCrc(long value) {
if (value >= 0 && value <= 0xFFFFFFFFL) {
@@ -296,12 +278,11 @@
/**
* Sets the extra information for this {@code ZipEntry}.
- *
+ *
* @param data
* a byte array containing the extra information.
* @throws IllegalArgumentException
* when the length of data is greater than 0xFFFF bytes.
- * @since Android 1.0
*/
public void setExtra(byte[] data) {
if (data == null || data.length <= 0xFFFF) {
@@ -313,13 +294,12 @@
/**
* Sets the compression method for this {@code ZipEntry}.
- *
+ *
* @param value
* the compression method, either {@code DEFLATED} or {@code
* STORED}.
* @throws IllegalArgumentException
* when value is not {@code DEFLATED} or {@code STORED}.
- * @since Android 1.0
*/
public void setMethod(int value) {
if (value != STORED && value != DEFLATED) {
@@ -330,12 +310,11 @@
/**
* Sets the uncompressed size of this {@code ZipEntry}.
- *
+ *
* @param value
* the uncompressed size for this entry.
* @throws IllegalArgumentException
* if {@code value} < 0 or {@code value} > 0xFFFFFFFFL.
- * @since Android 1.0
*/
public void setSize(long value) {
if (value >= 0 && value <= 0xFFFFFFFFL) {
@@ -347,11 +326,10 @@
/**
* Sets the modification time of this {@code ZipEntry}.
- *
+ *
* @param value
* the modification time as the number of milliseconds since Jan.
* 1, 1970.
- * @since Android 1.0
*/
public void setTime(long value) {
GregorianCalendar cal = new GregorianCalendar();
@@ -372,9 +350,8 @@
/**
* Returns the string representation of this {@code ZipEntry}.
- *
+ *
* @return the string representation of this {@code ZipEntry}.
- * @since Android 1.0
*/
@Override
public String toString() {
@@ -401,10 +378,9 @@
/**
* Constructs a new {@code ZipEntry} using the values obtained from {@code
* ze}.
- *
+ *
* @param ze
* the {@code ZipEntry} from which to obtain values.
- * @since Android 1.0
*/
public ZipEntry(ZipEntry ze) {
name = ze.name;
@@ -434,9 +410,8 @@
/**
* Returns a shallow copy of this entry.
- *
+ *
* @return a copy of this entry.
- * @since Android 1.0
*/
@Override
public Object clone() {
@@ -445,9 +420,8 @@
/**
* Returns the hash code for this {@code ZipEntry}.
- *
+ *
* @return the hash code of the entry.
- * @since Android 1.0
*/
@Override
public int hashCode() {
@@ -471,7 +445,7 @@
* readIntLE, so we're going to read the entire header at once
* and then parse the results out without using any function calls.
* Uglier, but should be much faster.
- *
+ *
* Note that some lines look a bit different, because the corresponding
* fields or locals are long and so we need to do & 0xffffffffl to avoid
* problems induced by sign extension.
@@ -549,7 +523,7 @@
int count;
int len = b.length;
int off = 0;
-
+
while (len > 0) {
count = in.read(b, off, len);
if (count <= 0)
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipException.java b/libcore/archive/src/main/java/java/util/zip/ZipException.java
index 590117b..6dab26f 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipException.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipException.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.IOException;
/**
@@ -26,7 +25,6 @@
*
* @see ZipFile
* @see ZipInputStream
- * @since Android 1.0
*/
public class ZipException extends IOException {
@@ -34,8 +32,6 @@
/**
* Constructs a new {@code ZipException} instance.
- *
- * @since Android 1.0
*/
public ZipException() {
super();
@@ -44,10 +40,9 @@
/**
* Constructs a new {@code ZipException} instance with the specified
* message.
- *
+ *
* @param detailMessage
* the detail message for the exception.
- * @since Android 1.0
*/
public ZipException(String detailMessage) {
super(detailMessage);
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipFile.java b/libcore/archive/src/main/java/java/util/zip/ZipFile.java
index f1415d9..653b2c9 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipFile.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipFile.java
@@ -37,17 +37,13 @@
* While {@code ZipInputStream} provides stream based read access to a
* <i>ZIP-archive</i>, this class implements more efficient (file based) access
* and makes use of the <i>central directory</i> within a <i>ZIP-archive</i>.
- * </p>
* <p>
* Use {@code ZipOutputStream} if you want to create an archive.
- * </p>
* <p>
* A temporary ZIP file can be marked for automatic deletion upon closing it.
- * </p>
- *
+ *
* @see ZipEntry
* @see ZipOutputStream
- * @since Android 1.0
*/
public class ZipFile implements ZipConstants {
@@ -57,28 +53,23 @@
/**
* Open zip file for read.
- *
- * @since Android 1.0
*/
public static final int OPEN_READ = 1;
/**
* Delete zip file when closed.
- *
- * @since Android 1.0
*/
public static final int OPEN_DELETE = 4;
/**
* Constructs a new {@code ZipFile} with the specified file.
- *
+ *
* @param file
* the file to read from.
* @throws ZipException
* if a ZIP error occurs.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public ZipFile(File file) throws ZipException, IOException {
this(file, OPEN_READ);
@@ -88,22 +79,31 @@
* Opens a file as <i>ZIP-archive</i>. "mode" must be {@code OPEN_READ} or
* {@code OPEN_DELETE} . The latter sets the "delete on exit" flag through a
* file.
- *
+ *
* @param file
* the ZIP file to read.
* @param mode
* the mode of the file open operation.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public ZipFile(File file, int mode) throws IOException {
- if (mode == (OPEN_READ | OPEN_DELETE))
- fileToDeleteOnClose = file; // file.deleteOnExit();
- else if (mode != OPEN_READ)
- throw new IllegalArgumentException("invalid mode");
-
fileName = file.getPath();
+ if (mode == OPEN_READ || mode == (OPEN_READ | OPEN_DELETE)) {
+ SecurityManager security = System.getSecurityManager();
+ if (security != null) {
+ security.checkRead(fileName);
+ }
+ if ((mode & OPEN_DELETE) != 0) {
+ if (security != null) {
+ security.checkDelete(fileName);
+ }
+ fileToDeleteOnClose = file; // file.deleteOnExit();
+ }
+ } else {
+ throw new IllegalArgumentException();
+ }
+
mRaf = new RandomAccessFile(fileName, "r");
mEntryList = new ArrayList<ZipEntry>();
@@ -124,12 +124,11 @@
/**
* Opens a ZIP archived file.
- *
+ *
* @param name
* the name of the ZIP file.
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
public ZipFile(String name) throws IOException {
this(new File(name), OPEN_READ);
@@ -142,10 +141,9 @@
/**
* Closes this ZIP file.
- *
+ *
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
public void close() throws IOException {
RandomAccessFile raf = mRaf;
@@ -171,9 +169,8 @@
/**
* Returns an enumeration of the entries. The entries are listed in the
* order in which they appear in the ZIP archive.
- *
+ *
* @return the enumeration of the entries.
- * @since Android 1.0
*/
public Enumeration<? extends ZipEntry> entries() {
return new Enumeration<ZipEntry>() {
@@ -195,12 +192,11 @@
/**
* Gets the ZIP entry with the specified name from this {@code ZipFile}.
- *
+ *
* @param entryName
* the name of the entry in the ZIP file.
* @return a {@code ZipEntry} or {@code null} if the entry name does not
* exist in the ZIP file.
- * @since Android 1.0
*/
public ZipEntry getEntry(String entryName) {
if (entryName != null) {
@@ -213,13 +209,12 @@
/**
* Returns an input stream on the data of the specified {@code ZipEntry}.
- *
+ *
* @param entry
* the ZipEntry.
* @return an input stream of the data contained in the {@code ZipEntry}.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public InputStream getInputStream(ZipEntry entry) throws IOException {
/*
@@ -259,9 +254,8 @@
/**
* Gets the file name of this {@code ZipFile}.
- *
+ *
* @return the file name of this {@code ZipFile}.
- * @since Android 1.0
*/
public String getName() {
return fileName;
@@ -269,9 +263,8 @@
/**
* Returns the number of {@code ZipEntries} in this {@code ZipFile}.
- *
+ *
* @return the number of entries in this file.
- * @since Android 1.0
*/
public int size() {
return mEntryList.size();
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java b/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java
index 262fa3f..1a35b1c 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipInputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -36,18 +35,14 @@
* the so called ZIP entries. Therefore when reading from a {@code
* ZipInputStream} first the entry's attributes will be retrieved with {@code
* getNextEntry} before its data is read.
- * </p>
* <p>
* While {@code InflaterInputStream} can read a compressed <i>ZIP-archive</i>
* entry, this extension can read uncompressed entries as well.
- * </p>
* <p>
* Use {@code ZipFile} if you can access the archive as a file directly.
- * </p>
- *
+ *
* @see ZipEntry
* @see ZipFile
- * @since Android 1.0
*/
public class ZipInputStream extends InflaterInputStream implements ZipConstants {
static final int DEFLATED = 8;
@@ -58,7 +53,7 @@
static final int ZIPLocalHeaderVersionNeeded = 20;
- // BEGI android-removed
+ // BEGIN android-removed
// private boolean zipClosed = false;
// END android-removed
@@ -82,10 +77,9 @@
/**
* Constructs a new {@code ZipInputStream} from the specified input stream.
- *
+ *
* @param stream
* the input stream to representing a ZIP archive.
- * @since Android 1.0
*/
public ZipInputStream(InputStream stream) {
super(new PushbackInputStream(stream, BUF_SIZE), new Inflater(true));
@@ -96,10 +90,9 @@
/**
* Closes this {@code ZipInputStream}.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -113,10 +106,9 @@
/**
* Closes the current ZIP entry and positions to read the next entry.
- *
+ *
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
public void closeEntry() throws IOException {
// BEGIN android-changed
@@ -173,13 +165,12 @@
/**
* Reads the next entry from this {@code ZipInputStream}.
- *
+ *
* @return the next {@code ZipEntry} contained in the input stream.
* @throws IOException
* if the stream is not positioned at the beginning of an entry
* or if an other {@code IOException} occurs.
* @see ZipEntry
- * @since Android 1.0
*/
public ZipEntry getNextEntry() throws IOException {
if (currentEntry != null) {
@@ -274,6 +265,18 @@
/* Read 4 bytes from the buffer and store it as an int */
+ /**
+ * Reads up to the specified number of uncompressed bytes into the buffer
+ * starting at the offset.
+ *
+ * @param buffer
+ * a byte array
+ * @param start
+ * the starting offset into the buffer
+ * @param length
+ * the number of bytes to read
+ * @return the number of bytes read
+ */
@Override
public int read(byte[] buffer, int start, int length) throws IOException {
// BEGIN android-changed
@@ -340,13 +343,12 @@
/**
* Skips up to the specified number of bytes in the current ZIP entry.
- *
+ *
* @param value
* the number of bytes to skip.
* @return the number of bytes skipped.
* @throws IOException
* if an {@code IOException} occurs.
- * @since Android 1.0
*/
@Override
public long skip(long value) throws IOException {
@@ -364,15 +366,14 @@
return skipped;
}
throw new IllegalArgumentException();
-}
+ }
/**
* Returns 0 if the {@code EOF} has been reached, otherwise returns 1.
- *
+ *
* @return 0 after {@code EOF} of current entry, 1 otherwise.
* @throws IOException
* if an IOException occurs.
- * @since Android 1.0
*/
@Override
public int available() throws IOException {
@@ -389,11 +390,10 @@
/**
* creates a {@link ZipEntry } with the given name.
- *
+ *
* @param name
* the name of the entry.
* @return the created {@code ZipEntry}.
- * @since Android 1.0
*/
protected ZipEntry createZipEntry(String name) {
return new ZipEntry(name);
diff --git a/libcore/archive/src/main/java/java/util/zip/ZipOutputStream.java b/libcore/archive/src/main/java/java/util/zip/ZipOutputStream.java
index 4ddf643..58e781f 100644
--- a/libcore/archive/src/main/java/java/util/zip/ZipOutputStream.java
+++ b/libcore/archive/src/main/java/java/util/zip/ZipOutputStream.java
@@ -17,7 +17,6 @@
package java.util.zip;
-
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
@@ -32,33 +31,26 @@
* {@code ZipOutputStream} is used to write {@code ZipEntries} to the underlying
* stream. Output from {@code ZipOutputStream} conforms to the {@code ZipFile}
* file format.
- * </p>
* <p>
* While {@code DeflaterOutputStream} can write a compressed <i>ZIP-archive</i>
* entry, this extension can write uncompressed entries as well. In this case
* special rules apply, for this purpose refer to the <a
* href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">file format
* specification</a>.
- * </p>
- *
+ *
* @see ZipEntry
* @see ZipFile
- * @since Android 1.0
*/
public class ZipOutputStream extends DeflaterOutputStream implements
ZipConstants {
/**
* Indicates deflated entries.
- *
- * @since Android 1.0
*/
public static final int DEFLATED = 8;
/**
* Indicates uncompressed entries.
- *
- * @since Android 1.0
*/
public static final int STORED = 0;
@@ -90,7 +82,6 @@
*
* @param p1
* the {@code OutputStream} to write the data to.
- * @since Android 1.0
*/
public ZipOutputStream(OutputStream p1) {
super(p1, new Deflater(Deflater.DEFAULT_COMPRESSION, true));
@@ -102,7 +93,6 @@
*
* @throws IOException
* If an error occurs closing the stream.
- * @since Android 1.0
*/
@Override
public void close() throws IOException {
@@ -119,7 +109,6 @@
*
* @throws IOException
* If an error occurs closing the entry.
- * @since Android 1.0
*/
public void closeEntry() throws IOException {
if (cDir == null) {
@@ -205,7 +194,6 @@
*
* @throws IOException
* if an error occurs while terminating the stream.
- * @since Android 1.0
*/
@Override
public void finish() throws IOException {
@@ -253,7 +241,6 @@
* @throws IOException
* If an error occurs storing the entry.
* @see #write
- * @since Android 1.0
*/
public void putNextEntry(ZipEntry ze) throws java.io.IOException {
if (currentEntry != null) {
@@ -286,7 +273,8 @@
nameLength = utf8Count(ze.name);
if (nameLength > 0xffff) {
/* [MSG "archive.2A", "Name too long: {0}"] */
- throw new IllegalArgumentException(Messages.getString("archive.2A", ze.name)); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString(
+ "archive.2A", ze.name)); //$NON-NLS-1$
}
def.setLevel(compressLevel);
@@ -338,7 +326,6 @@
*
* @param comment
* the comment associated with the file.
- * @since Android 1.0
*/
public void setComment(String comment) {
if (comment.length() > 0xFFFF) {
@@ -355,7 +342,6 @@
* @param level
* the compression level (ranging from -1 to 8).
* @see Deflater
- * @since Android 1.0
*/
public void setLevel(int level) {
if (level < Deflater.DEFAULT_COMPRESSION
@@ -372,7 +358,6 @@
*
* @param method
* the compression method to use.
- * @since Android 1.0
*/
public void setMethod(int method) {
if (method != STORED && method != DEFLATED) {
@@ -398,11 +383,17 @@
}
+ /**
+ * Writes data for the current entry to the underlying stream.
+ *
+ * @exception IOException
+ * If an error occurs writing to the stream
+ */
@Override
public void write(byte[] buffer, int off, int nbytes)
throws java.io.IOException {
// avoid int overflow, check null buf
- if ((off > buffer.length) || (nbytes < 0) || (off < 0)
+ if ((off < 0 || (nbytes < 0) || off > buffer.length)
|| (buffer.length - off < nbytes)) {
throw new IndexOutOfBoundsException();
}
diff --git a/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java b/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
index 764f34d..3ba50fa 100644
--- a/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
+++ b/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/Messages.java
@@ -27,7 +27,6 @@
package org.apache.harmony.archive.internal.nls;
-
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
@@ -50,7 +49,7 @@
* 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 {
@@ -61,7 +60,7 @@
/**
* 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.
@@ -74,7 +73,7 @@
/**
* Retrieves a message which takes 1 argument.
- *
+ *
* @param msg
* String the key to look up.
* @param arg
@@ -87,7 +86,7 @@
/**
* Retrieves a message which takes 1 integer argument.
- *
+ *
* @param msg
* String the key to look up.
* @param arg
@@ -100,7 +99,7 @@
/**
* Retrieves a message which takes 1 character argument.
- *
+ *
* @param msg
* String the key to look up.
* @param arg
@@ -113,7 +112,7 @@
/**
* Retrieves a message which takes 2 arguments.
- *
+ *
* @param msg
* String the key to look up.
* @param arg1
@@ -128,7 +127,7 @@
/**
* Retrieves a message which takes several arguments.
- *
+ *
* @param msg
* String the key to look up.
* @param args
diff --git a/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties b/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
index 1ae5c5e..e909af0 100644
--- a/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
+++ b/libcore/archive/src/main/java/org/apache/harmony/archive/internal/nls/messages.properties
@@ -60,8 +60,11 @@
archive.2A=Name too long: {0}
archive.2B=String is too long
archive.2C=No active entry
-archive.2D=Missing version string\: {0}
-archive.2E=Line too long
-archive.2F=Invalid attribute {0}
-archive.30={0} failed verification of {1}
-archive.31={0} has invalid digest for {1} in {2}
+archive.2D=Missing version attribute\: {0}
+archive.2E=Manifest is too long
+archive.2F=NUL character in a manifest
+archive.30=Invalid attribute {0}
+archive.31={0} failed verification of {1}
+archive.32={0} has invalid digest for {1} in {2}
+archive.33=A length of the encoded header name "{1}" exceeded maximum length {2}
+archive.34=A jar verifier does not support more than one entry with the same name
diff --git a/libcore/archive/src/main/java/org/apache/harmony/archive/util/Util.java b/libcore/archive/src/main/java/org/apache/harmony/archive/util/Util.java
index bed3e91..b15108a 100644
--- a/libcore/archive/src/main/java/org/apache/harmony/archive/util/Util.java
+++ b/libcore/archive/src/main/java/org/apache/harmony/archive/util/Util.java
@@ -30,39 +30,49 @@
return false;
}
- s1 = s1.substring(start1, start1 + length);
- s2 = s2.substring(start2, start2 + length);
-
- return toASCIILowerCase(s1).equals(toASCIILowerCase(s2));
+ char c1, c2;
+ for (int i = 0; i < length; i++) {
+ if ((c1 = s1.charAt(start1++)) != (c2 = s2.charAt(start2++))
+ && toASCIIUpperCase(c1) != toASCIIUpperCase(c2)) {
+ return false;
+ }
+ }
+ return true;
}
throw new NullPointerException();
}
- public static String toASCIILowerCase(String s) {
- int len = s.length();
- StringBuilder buffer = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- if ('A' <= c && c <= 'Z') {
- buffer.append((char) (c + ('a' - 'A')));
- } else {
- buffer.append(c);
+ public static final boolean equalsIgnoreCase(byte[] buf1, byte[] buf2) {
+ if (buf1 == buf2) {
+ return true;
+ }
+
+ if (buf1 == null || buf2 == null || buf1.length != buf2.length) {
+ return false;
+ }
+
+ byte b1, b2;
+
+ for (int i = 0; i < buf1.length; i++) {
+ if ((b1 = buf1[i]) != (b2 = buf2[i])
+ && toASCIIUpperCase(b1) != toASCIIUpperCase(b2)) {
+ return false;
}
}
- return buffer.toString();
+ return true;
}
- public static String toASCIIUpperCase(String s) {
- int len = s.length();
- StringBuilder buffer = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char c = s.charAt(i);
- if ('a' <= c && c <= 'z') {
- buffer.append((char) (c - ('a' - 'A')));
- } else {
- buffer.append(c);
- }
+ static final char toASCIIUpperCase(char c) {
+ if ('a' <= c && c <= 'z') {
+ return (char) (c - ('a' - 'A'));
}
- return buffer.toString();
+ return c;
+ }
+
+ static final byte toASCIIUpperCase(byte b) {
+ if ('a' <= b && b <= 'z') {
+ return (byte) (b - ('a' - 'A'));
+ }
+ return b;
}
}
diff --git a/libcore/archive/src/main/native/java_util_zip_Adler32.c b/libcore/archive/src/main/native/java_util_zip_Adler32.c
index a7a182a..1b02a11 100644
--- a/libcore/archive/src/main/native/java_util_zip_Adler32.c
+++ b/libcore/archive/src/main/native/java_util_zip_Adler32.c
@@ -15,23 +15,25 @@
* limitations under the License.
*/
+#include "jni.h"
#include "hy2sie.h"
-
#include "zlib.h"
-
+#include "sieb.h"
JNIEXPORT jlong JNICALL
Java_java_util_zip_Adler32_updateImpl (JNIEnv * env, jobject recv,
jbyteArray buf, int off, int len,
jlong crc)
{
- PORT_ACCESS_FROM_ENV (env);
-
jbyte *b;
jboolean isCopy;
jlong result;
b = (*env)->GetPrimitiveArrayCritical (env, buf, &isCopy);
+ if (b == NULL) {
+ throwNewOutOfMemoryError(env, "");
+ return 0;
+ }
result = (jlong) adler32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
(*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT);
@@ -42,9 +44,8 @@
Java_java_util_zip_Adler32_updateByteImpl (JNIEnv * env, jobject recv,
jint val, jlong crc)
{
- PORT_ACCESS_FROM_ENV (env);
-
- return adler32 ((uLong) crc, (Bytef *) (&val), 1);
+ Bytef bytefVal = val;
+ return adler32 ((uLong) crc, (Bytef *) (&bytefVal), 1);
}
diff --git a/libcore/archive/src/main/native/java_util_zip_CRC32.c b/libcore/archive/src/main/native/java_util_zip_CRC32.c
index 0688868..cee25e5 100644
--- a/libcore/archive/src/main/native/java_util_zip_CRC32.c
+++ b/libcore/archive/src/main/native/java_util_zip_CRC32.c
@@ -16,6 +16,7 @@
*/
#include "hy2sie.h"
+#include "sieb.h"
#include "zlib.h"
@@ -28,8 +29,10 @@
jlong result;
b = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (b == NULL)
+ if (b == NULL) {
+ throwNewOutOfMemoryError(env, "");
return -1;
+ }
result = crc32 ((uLong) crc, (Bytef *) (b + off), (uInt) len);
((*env)->ReleasePrimitiveArrayCritical (env, buf, b, JNI_ABORT));
return result;
diff --git a/libcore/archive/src/main/native/java_util_zip_Deflater.c b/libcore/archive/src/main/native/java_util_zip_Deflater.c
index c8bd199..2e0e268 100644
--- a/libcore/archive/src/main/native/java_util_zip_Deflater.c
+++ b/libcore/archive/src/main/native/java_util_zip_Deflater.c
@@ -18,11 +18,13 @@
#include "hy2sie.h"
#include "zlib.h"
-#include "zipsup.h"
+#include "zip.h"
+#include "jni.h"
-
+#ifndef HY_ZIP_API
void zfree PROTOTYPE ((void *opaque, void *address));
void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
+#endif
static struct {
@@ -52,10 +54,10 @@
if (err != Z_OK)
{
jclmem_free_memory (env, dBytes);
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return;
}
- stream->dict = dBytes;
+ stream->dict = (U_8*) dBytes;
}
JNIEXPORT jlong JNICALL
@@ -94,9 +96,8 @@
Java_java_util_zip_Deflater_createStream (JNIEnv * env, jobject recv,
jint level, jint strategy,
jboolean noHeader)
-{
+{
PORT_ACCESS_FROM_ENV (env);
-
JCLZipStream *jstream;
z_stream *stream;
int err = 0;
@@ -109,7 +110,12 @@
// results in 2 x 128K being allocated per Deflater, which is
// not acceptable.
// END android-changed
-
+#ifdef HY_ZIP_API
+ VMI_ACCESS_FROM_ENV (env);
+ VMIZipFunctionTable *zipFuncs;
+ zipFuncs = (*VMI)->GetZipFunctions(VMI);
+#endif
+
/*Allocate mem for wrapped struct */
jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream));
if (jstream == NULL)
@@ -141,11 +147,10 @@
mlevel, /*Memory allocation for internal compression state. 9 uses the most. */
// END android-changed
strategy);
- if (err != Z_OK)
- {
- throwNewIllegalArgumentException (env, "");
- return -1;
- }
+ if (err != Z_OK) {
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
+ return -1;
+ }
return (jlong) ((IDATA) jstream);
}
@@ -170,8 +175,10 @@
return;
}
in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (in == NULL)
+ if (in == NULL) {
+ throwNewOutOfMemoryError(env, "");
return;
+ }
memcpy (stream->inaddr, (in + off), len);
((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
stream->stream->next_in = (Bytef *) stream->inaddr;
@@ -185,8 +192,6 @@
jbyteArray buf, int off, int len,
jlong handle, int flushParm)
{
- PORT_ACCESS_FROM_ENV (env);
-
jbyte *out;
JCLZipStream *stream;
jint err = 0;
@@ -203,29 +208,34 @@
sin = stream->stream->total_in;
sout = stream->stream->total_out;
out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (out == NULL)
+ if (out == NULL) {
+ throwNewOutOfMemoryError(env, "");
return -1;
+ }
stream->stream->next_out = (Bytef *) out + off;
err = deflate (stream->stream, flushParm);
((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0));
- if (err != Z_OK)
- {
- if (err == Z_STREAM_END)
- {
- ((*env)->
- SetBooleanField (env, recv,
- gCachedFields.finished,
- JNI_TRUE));
- return stream->stream->total_out - sout;
- }
+ if (err != Z_OK) {
+ if (err == Z_MEM_ERROR) {
+ throwNewOutOfMemoryError(env, "");
+ return 0;
}
+ if (err == Z_STREAM_END)
+ {
+ ((*env)->
+ SetBooleanField (env, recv,
+ gCachedFields.finished,
+ JNI_TRUE));
+ return stream->stream->total_out - sout;
+ }
+ }
if (flushParm != Z_FINISH)
{
/* Need to update the number of input bytes read. */
((*env)->
SetIntField (env, recv,
- gCachedFields.inRead,
- (jint) stream->stream->total_in - sin + inBytes));
+ gCachedFields.inRead,
+ (jint) stream->stream->total_in - sin + inBytes));
}
return stream->stream->total_out - sout;
}
@@ -262,8 +272,6 @@
int level, int strategy,
jlong handle)
{
- PORT_ACCESS_FROM_ENV (env);
-
JCLZipStream *stream;
jbyte b = 0;
int err = 0;
@@ -276,8 +284,9 @@
stream = (JCLZipStream *) ((IDATA) handle);
stream->stream->next_out = (Bytef *) & b;
err = deflateParams (stream->stream, level, strategy);
- if (err != Z_OK)
- throwNewIllegalStateException (env, "");
+ if (err != Z_OK) {
+ THROW_ZIP_EXCEPTION(env, err, IllegalStateException);
+ }
}
JNIEXPORT void JNICALL
diff --git a/libcore/archive/src/main/native/java_util_zip_Inflater.c b/libcore/archive/src/main/native/java_util_zip_Inflater.c
index d3a7d7c..4b30d4e 100644
--- a/libcore/archive/src/main/native/java_util_zip_Inflater.c
+++ b/libcore/archive/src/main/native/java_util_zip_Inflater.c
@@ -16,6 +16,7 @@
*/
#include "hy2sie.h"
+#include "zip.h"
#include "zlib.h"
#include <memory.h>
@@ -24,6 +25,7 @@
#include <fcntl.h>
+void throwNewDataFormatException (JNIEnv * env, const char *message);
void zfree PROTOTYPE ((void *opaque, void *address));
void *zalloc PROTOTYPE ((void *opaque, U_32 items, U_32 size));
@@ -36,27 +38,6 @@
} gCachedFields;
-// Contents from Harmony's inflater.h was put here:
-//
-typedef struct JCLZipStream
-{
- U_8 *inaddr;
- int inCap;
- U_8 *dict;
- z_stream *stream;
-} JCLZipStream;
-
-
-
-/**
- * Throw java.util.zip.DataFormatException
- */
-void
-throwNewDataFormatException (JNIEnv * env, const char *message)
-{
- jniThrowException(env, "java/util/zip/DataFormatException", message);
-}
-
/* Create a new stream . This stream cannot be used until it has been properly initialized. */
JNIEXPORT jlong JNICALL
@@ -69,6 +50,11 @@
z_stream *stream;
int err = 0;
int wbits = 15; /*Use MAX for fastest */
+#ifdef HY_ZIP_API
+ VMI_ACCESS_FROM_ENV (env);
+ VMIZipFunctionTable *zipFuncs;
+ zipFuncs = (*VMI)->GetZipFunctions(VMI);
+#endif
/*Allocate mem for wrapped struct */
jstream = jclmem_allocate_memory (env, sizeof (JCLZipStream));
@@ -104,7 +90,7 @@
{
jclmem_free_memory (env, stream);
jclmem_free_memory (env, jstream);
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return -1;
}
@@ -134,8 +120,10 @@
stream->stream->next_in = (Bytef *) baseAddr;
stream->stream->avail_in = len;
in = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
- if (in == NULL)
+ if (in == NULL) {
+ throwNewOutOfMemoryError(env, "");
return;
+ }
memcpy (baseAddr, (in + off), len);
((*env)->ReleasePrimitiveArrayCritical (env, buf, in, JNI_ABORT));
return;
@@ -176,8 +164,6 @@
jbyteArray buf, int off, int len,
jlong handle)
{
- PORT_ACCESS_FROM_ENV (env);
-
jbyte *out;
JCLZipStream *stream = (JCLZipStream *) ((IDATA) handle);
jint err = 0;
@@ -192,9 +178,10 @@
sin = stream->stream->total_in;
sout = stream->stream->total_out;
out = ((*env)->GetPrimitiveArrayCritical (env, buf, 0));
-
- if (out == NULL)
+ if (out == NULL) {
+ throwNewOutOfMemoryError(env, "");
return -1;
+ }
stream->stream->next_out = (Bytef *) out + off;
err = inflate (stream->stream, Z_SYNC_FLUSH);
((*env)->ReleasePrimitiveArrayCritical (env, buf, out, 0));
@@ -217,7 +204,7 @@
}
else
{
- throwNewDataFormatException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, DataFormatException);
return -1;
}
}
@@ -280,7 +267,7 @@
if (err != Z_OK)
{
jclmem_free_memory (env, dBytes);
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return;
}
stream->dict = dBytes;
@@ -297,11 +284,19 @@
err = inflateReset (stream->stream);
if (err != Z_OK)
{
- throwNewIllegalArgumentException (env, "");
+ THROW_ZIP_EXCEPTION(env, err, IllegalArgumentException);
return;
}
}
+/**
+ * Throw java.util.zip.DataFormatException
+ */
+void
+throwNewDataFormatException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/util/zip/DataFormatException", message);
+}
JNIEXPORT jlong JNICALL
Java_java_util_zip_Inflater_getTotalOutImpl (JNIEnv * env, jobject recv,
@@ -311,6 +306,7 @@
stream = (JCLZipStream *) ((IDATA) handle);
return stream->stream->total_out;
+
}
JNIEXPORT jlong JNICALL
diff --git a/libcore/archive/src/main/native/sieb.c b/libcore/archive/src/main/native/sieb.c
index ab9430b..6881cf6 100644
--- a/libcore/archive/src/main/native/sieb.c
+++ b/libcore/archive/src/main/native/sieb.c
@@ -10,20 +10,6 @@
jniThrowException(env, "java/lang/OutOfMemoryError", message);
}
-// Throw java.lang.IllegalStateException
-void throwNewIllegalStateException (JNIEnv * env, const char *message)
-{
- jniThrowException(env, "java/lang/IllegalStateException", message);
-}
-
-// Throw java.lang.IllegalArgumentException
-void throwNewIllegalArgumentException (JNIEnv * env, const char *message)
-{
- jniThrowException(env, "java/lang/IllegalArgumentException", message);
-}
-
-
-
void * sieb_malloc (JNIEnv * env, size_t byteCnt) {
void * adr = malloc(byteCnt);
if (adr == 0) {
diff --git a/libcore/archive/src/main/native/sieb.h b/libcore/archive/src/main/native/sieb.h
index 536c806..541ad90 100644
--- a/libcore/archive/src/main/native/sieb.h
+++ b/libcore/archive/src/main/native/sieb.h
@@ -7,9 +7,8 @@
-void throwNewOutOfMemoryError (JNIEnv * env, const char *message);
-void throwNewIllegalArgumentException (JNIEnv * env, const char *message);
-void throwNewIllegalStateException (JNIEnv * env, const char *message);
+void throwNewOutOfMemoryError (JNIEnv * env,
+ const char *message);
void * sieb_malloc (JNIEnv * env, size_t byteCnt);
diff --git a/libcore/archive/src/main/native/sub.mk b/libcore/archive/src/main/native/sub.mk
index 047c319..694c185 100644
--- a/libcore/archive/src/main/native/sub.mk
+++ b/libcore/archive/src/main/native/sub.mk
@@ -7,7 +7,8 @@
java_util_zip_CRC32.c \
java_util_zip_Deflater.c \
java_util_zip_Inflater.c \
- zipalloc.c \
+ zip.c \
+ zipalloc.c \
sieb.c
LOCAL_C_INCLUDES += \
diff --git a/libcore/archive/src/main/native/zip.c b/libcore/archive/src/main/native/zip.c
new file mode 100644
index 0000000..3d15d2a
--- /dev/null
+++ b/libcore/archive/src/main/native/zip.c
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#include "zip.h"
+#include "jni.h"
+
+/**
+ * Throw java.lang.IllegalStateException
+ */
+void
+throwNewIllegalStateException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/IllegalStateException", message);
+}
+
+/**
+ * Throw java.lang.IllegalArgumentException
+ */
+void
+throwNewIllegalArgumentException (JNIEnv * env, const char *message)
+{
+ jniThrowException(env, "java/lang/IllegalArgumentException", message);
+}
diff --git a/libcore/archive/src/main/native/zip.h b/libcore/archive/src/main/native/zip.h
new file mode 100644
index 0000000..1452073
--- /dev/null
+++ b/libcore/archive/src/main/native/zip.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#if !defined(zip_h)
+#define zip_h
+
+#ifndef HY_ZIP_API
+#include "zipsup.h"
+#else /* HY_ZIP_API */
+#include "vmizip.h"
+#endif /* HY_ZIP_API */
+
+#include "hymutex.h"
+
+typedef struct JCLZipFile
+{
+ struct JCLZipFile *last;
+ struct JCLZipFile *next;
+#ifndef HY_ZIP_API
+ HyZipFile hyZipFile;
+#else
+ VMIZipFile hyZipFile;
+#endif
+} JCLZipFile;
+
+/* Fake JCLZipFile entry. last, next must be in the same position as JCLZipFile */
+typedef struct JCLZipFileLink
+{
+ JCLZipFile *last;
+ JCLZipFile *next;
+ MUTEX mutex;
+} JCLZipFileLink;
+
+// Contents from Harmony's inflater.h was put here:
+//
+typedef struct JCLZipStream
+{
+ U_8 *inaddr;
+ int inCap;
+ U_8 *dict;
+ z_stream *stream;
+} JCLZipStream;
+
+#define THROW_ZIP_EXCEPTION(env, err, type) \
+ if (err == Z_MEM_ERROR) { \
+ throwNewOutOfMemoryError(env, ""); \
+ } else { \
+ throwNew##type(env, (const char*) zError(err)); \
+ }
+
+void throwNewIllegalStateException PROTOTYPE((JNIEnv* env,
+ const char* message));
+void throwNewIllegalArgumentException PROTOTYPE((JNIEnv* env,
+ const char* message));
+
+#endif /* zip_h */
diff --git a/libcore/archive/src/main/native/zipsup.c b/libcore/archive/src/main/native/zipsup.c
index 1bbe51f..22ea7e9 100644
--- a/libcore/archive/src/main/native/zipsup.c
+++ b/libcore/archive/src/main/native/zipsup.c
@@ -1438,7 +1438,7 @@
return ZIP_ERR_FILE_CORRUPT; /* should never happen! */
}
result = zip_establishCache (portLib, zipFile);
- if (result)
+ if (!result)
{
/* (silently start operating without a cache if we couldn't make a new one) */
}
diff --git a/libcore/archive/src/main/native/zipsup.h b/libcore/archive/src/main/native/zipsup.h
index adc086a..67a2eda 100644
--- a/libcore/archive/src/main/native/zipsup.h
+++ b/libcore/archive/src/main/native/zipsup.h
@@ -34,23 +34,17 @@
#include "zlib.h"
-// Contents from Harmony's inflater.h was put here:
-//
-typedef struct JCLZipStream
-{
- U_8 *inaddr;
- U_8 *dict;
- z_stream *stream;
-} JCLZipStream;
-
-
typedef struct HyZipCachePool HyZipCachePool;
HyZipCachePool *
zipsup_GetZipCachePool(HyPortLibrary * portLib);
+#if defined(HY_LOCAL_ZLIB)
+#define HY_ZIP_DLL_NAME "z"
+#else
#define HY_ZIP_DLL_NAME "hyzlib"
+#endif
#define ZIP_INTERNAL_MAX 80
#define ZIP_CM_Reduced1 2
@@ -156,18 +150,6 @@
-// Contents from Harmony's zip.h were put in java_util_zip_ZipFile.c
-// and here:
-typedef struct JCLZipFile
-{
- struct JCLZipFile *last;
- struct JCLZipFile *next;
- HyZipFile hyZipFile;
-} JCLZipFile;
-
-
-
-
#include "hymutex.h"
extern MUTEX zip_GlobalMutex;
diff --git a/libcore/archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java b/libcore/archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java
new file mode 100644
index 0000000..9c28dc2
--- /dev/null
+++ b/libcore/archive/src/test/java-internal/org/apache/harmony/archive/util/UtilTest.java
@@ -0,0 +1,87 @@
+/*
+ * 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.archive.util;
+
+import junit.framework.TestCase;
+
+public class UtilTest extends TestCase {
+ private static final String ASCII_ALPHABET_LC = "abcdefghijklmnopqrstuvwxyz";
+ private static final String ASCII_ALPHABET_UC = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ private static final byte[] ASCII_ALPHABET_LC_BYTES;
+ private static final byte[] ASCII_ALPHABET_UC_BYTES;
+
+ static {
+ ASCII_ALPHABET_LC_BYTES = new byte[ASCII_ALPHABET_LC.length()];
+ for (int i = 0; i < ASCII_ALPHABET_LC_BYTES.length; i++) {
+ final char c = ASCII_ALPHABET_LC.charAt(i);
+ final byte b = (byte) c;
+ assert ((char) b) == c;
+ ASCII_ALPHABET_LC_BYTES[i] = b;
+ }
+
+ ASCII_ALPHABET_UC_BYTES = new byte[ASCII_ALPHABET_UC.length()];
+ for (int i = 0; i < ASCII_ALPHABET_UC_BYTES.length; i++) {
+ final char c = ASCII_ALPHABET_UC.charAt(i);
+ final byte b = (byte) c;
+ assert ((char) b) == c;
+ ASCII_ALPHABET_UC_BYTES[i] = b;
+ }
+ }
+
+ public void testASCIIIgnoreCaseRegionMatches() {
+ final String s1 = ASCII_ALPHABET_LC;
+ final String s2 = ASCII_ALPHABET_UC;
+ for (int i = 0; i < s1.length(); i++) {
+ assertTrue(Util.ASCIIIgnoreCaseRegionMatches(s1, i, s2, i, s1
+ .length()
+ - i));
+ }
+ }
+
+ public void testToASCIIUpperCaseByte() {
+ for (int i = 0; i < ASCII_ALPHABET_LC_BYTES.length; i++) {
+ assertEquals(ASCII_ALPHABET_UC_BYTES[i], Util
+ .toASCIIUpperCase(ASCII_ALPHABET_LC_BYTES[i]));
+ }
+ for (int i = 0; i < ASCII_ALPHABET_UC_BYTES.length; i++) {
+ assertEquals(ASCII_ALPHABET_UC_BYTES[i], Util
+ .toASCIIUpperCase(ASCII_ALPHABET_UC_BYTES[i]));
+ }
+ }
+
+ public void testToASCIIUpperCaseChar() {
+ for (int i = 0; i < ASCII_ALPHABET_LC.length(); i++) {
+ assertEquals(ASCII_ALPHABET_UC.charAt(i), Util
+ .toASCIIUpperCase(ASCII_ALPHABET_LC.charAt(i)));
+ }
+ for (int i = 0; i < ASCII_ALPHABET_UC.length(); i++) {
+ assertEquals(ASCII_ALPHABET_UC.charAt(i), Util
+ .toASCIIUpperCase(ASCII_ALPHABET_UC.charAt(i)));
+ }
+ }
+
+ public void testEqualsIgnoreCaseByteArrayByteArray() {
+ assertTrue(Util.equalsIgnoreCase(ASCII_ALPHABET_LC_BYTES,
+ ASCII_ALPHABET_LC_BYTES));
+ assertTrue(Util.equalsIgnoreCase(ASCII_ALPHABET_LC_BYTES,
+ ASCII_ALPHABET_UC_BYTES));
+ assertTrue(Util.equalsIgnoreCase(ASCII_ALPHABET_UC_BYTES,
+ ASCII_ALPHABET_UC_BYTES));
+ }
+
+}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
index 0a8b037..0b3d2cf 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/AttributesTest.java
@@ -421,6 +421,27 @@
assertNull(attribute.get(name));
}
+ /**
+ * @tests java.util.jar.Attributes.hashCode()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
+ )
+ public void test_hashCode_consistent_with_map() {
+ MockAttributes mockAttr = new MockAttributes();
+ mockAttr.putValue("1", "one");
+ assertEquals(mockAttr.getMap().hashCode(), mockAttr.hashCode());
+ }
+
+ private static class MockAttributes extends Attributes {
+ public Map<Object, Object> getMap() {
+ return map;
+ }
+ }
+
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
@@ -470,7 +491,7 @@
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "hashCode",
args = {}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
index 40eff3b..90144be 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarEntryTest.java
@@ -72,6 +72,29 @@
}
/**
+ * @throws IOException
+ * @tests java.util.jar.JarEntry#JarEntry(java.util.jar.JarEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "JarEntry",
+ args = {java.util.jar.JarEntry.class}
+ )
+ public void test_ConstructorLjava_util_jar_JarEntry_on_null() throws IOException {
+ JarEntry newJarEntry = new JarEntry(jarFile.getJarEntry(entryName));
+ assertNotNull(newJarEntry);
+
+ jarEntry = null;
+ try {
+ newJarEntry = new JarEntry(jarEntry);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
* @tests java.util.jar.JarEntry#JarEntry(java.util.zip.ZipEntry)
*/
@TestTargetNew(
@@ -163,10 +186,21 @@
JarEntry jarEntry2 = jarFile.getJarEntry("Test.class");
InputStream in = jarFile.getInputStream(jarEntry1);
byte[] buffer = new byte[1024];
+ // BEGIN android-changed
+ // the certificates are non-null too early and in.available() fails
+ // while (in.available() > 0) {
+ // assertNull("getCertificates() should be null until the entry is read",
+ // jarEntry1.getCertificates());
+ // assertNull(jarEntry2.getCertificates());
+ // in.read(buffer);
+ // }
while (in.read(buffer) >= 0);
in.close();
+ // END android-changed
+ assertEquals("the file is fully read", -1, in.read());
assertNotNull(jarEntry1.getCertificates());
assertNotNull(jarEntry2.getCertificates());
+ in.close();
}
/**
@@ -187,8 +221,14 @@
InputStream in = jarFile.getInputStream(jarEntry);
byte[] buffer = new byte[1024];
while (in.available() > 0) {
+ // BEGIN android-changed
+ // the code signers are non-null too early
+ // assertNull("getCodeSigners() should be null until the entry is read",
+ // jarEntry.getCodeSigners());
+ // END android-changed
in.read(buffer);
}
+ assertEquals("the file is fully read", -1, in.read());
CodeSigner[] codeSigners = jarEntry.getCodeSigners();
assertEquals(2, codeSigners.length);
List<?> certs_bob = codeSigners[0].getSignerCertPath()
@@ -240,7 +280,7 @@
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "JarEntry",
args = {java.util.jar.JarEntry.class}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
index 720f78d..96321a4 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java
@@ -14,13 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.harmony.archive.tests.java.util.jar;
import dalvik.annotation.AndroidOnly;
import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargets;
import dalvik.annotation.TestLevel;
import dalvik.annotation.TestTargetNew;
@@ -73,13 +71,17 @@
private final String jarName3 = "hyts_manifest1.jar";
private final String jarName4 = "hyts_signed.jar";
-
+
private final String jarName5 = "hyts_signed_inc.jar";
+ private final String integrateJar = "Integrate.jar";
+
private final String entryName = "foo/bar/A.class";
private final String entryName3 = "coucou/FileAccess.class";
+ private final String integrateJarEntry = "Test.class";
+
private File resources;
// custom security manager
@@ -102,7 +104,7 @@
* @tests java.util.jar.JarFile#JarFile(java.io.File)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "JarFile",
args = {java.io.File.class}
@@ -300,6 +302,27 @@
}
/**
+ * Constructs JarFile object.
+ *
+ * @tests java.util.jar.JarFile#JarFile(java.io.File)
+ * @tests java.util.jar.JarFile#JarFile(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "JarFile",
+ args = {java.io.File.class}
+ )
+ public void testConstructor_file() throws IOException {
+ File f = new File(resources, jarName);
+ Support_Resources.copyFile(resources, null, jarName);
+ assertTrue(new JarFile(f).getEntry(entryName).getName().equals(
+ entryName));
+ assertTrue(new JarFile(f.getPath()).getEntry(entryName).getName()
+ .equals(entryName));
+ }
+
+ /**
* @tests java.util.jar.JarFile#entries()
*/
@TestTargetNew(
@@ -316,11 +339,11 @@
Support_Resources.copyFile(resources, null, jarName);
JarFile jarFile = new JarFile(new File(resources, jarName));
Enumeration<JarEntry> e = jarFile.entries();
- int i = 0;
- while (e.hasMoreElements()) {
- i++;
+ int i;
+ for (i = 0; e.hasMoreElements(); i++) {
e.nextElement();
}
+ assertEquals(jarFile.size(), i);
jarFile.close();
assertEquals(6, i);
}
@@ -336,24 +359,20 @@
JarFile jarFile = new JarFile(new File(resources, jarName));
Enumeration<JarEntry> enumeration = jarFile.entries();
jarFile.close();
- boolean pass = false;
try {
enumeration.hasMoreElements();
+ fail("hasMoreElements() did not detect a closed jar file");
} catch (IllegalStateException e) {
- pass = true;
}
- assertTrue("hasMoreElements did not detect closed jar file", pass);
Support_Resources.copyFile(resources, null, jarName);
jarFile = new JarFile(new File(resources, jarName));
enumeration = jarFile.entries();
jarFile.close();
- pass = false;
try {
enumeration.nextElement();
+ fail("nextElement() did not detect closed jar file");
} catch (IllegalStateException e) {
- pass = true;
}
- assertTrue("nextElement did not detect closed jar file", pass);
}
/**
@@ -361,7 +380,7 @@
* @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
+ level = TestLevel.PARTIAL_COMPLETE,
notes = "",
method = "getEntry",
args = {java.lang.String.class}
@@ -442,6 +461,92 @@
}
}
+
+ /**
+ * @tests java.util.jar.JarFile#getJarEntry(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "getEntry",
+ args = {java.lang.String.class}
+ )
+ public void testGetJarEntry() throws Exception {
+ Support_Resources.copyFile(resources, null, jarName);
+ JarFile jarFile = new JarFile(new File(resources, jarName));
+ assertEquals("Error in returned entry", 311, jarFile.getEntry(
+ entryName).getSize());
+ jarFile.close();
+
+ // tests for signed jars
+ // test all signed jars in the /Testres/Internal/SignedJars directory
+ String jarDirUrl = Support_Resources
+ .getResourceURL("/../internalres/signedjars");
+ Vector<String> signedJars = new Vector<String>();
+ try {
+ InputStream is = new URL(jarDirUrl + "/jarlist.txt").openStream();
+ while (is.available() > 0) {
+ StringBuilder linebuff = new StringBuilder(80); // Typical line
+ // length
+ done: while (true) {
+ int nextByte = is.read();
+ switch (nextByte) {
+ case -1:
+ break done;
+ case (byte) '\r':
+ if (linebuff.length() == 0) {
+ // ignore
+ }
+ break done;
+ case (byte) '\n':
+ if (linebuff.length() == 0) {
+ // ignore
+ }
+ break done;
+ default:
+ linebuff.append((char) nextByte);
+ }
+ }
+ if (linebuff.length() == 0) {
+ break;
+ }
+ String line = linebuff.toString();
+ signedJars.add(line);
+ }
+ is.close();
+ } catch (IOException e) {
+ // no list of jars found
+ }
+
+ for (int i = 0; i < signedJars.size(); i++) {
+ String jarName = signedJars.get(i);
+ try {
+ File file = Support_Resources.getExternalLocalFile(jarDirUrl
+ + "/" + jarName);
+ jarFile = new JarFile(file, true);
+ boolean foundCerts = false;
+ Enumeration<JarEntry> e = jarFile.entries();
+ while (e.hasMoreElements()) {
+ JarEntry entry = e.nextElement();
+ InputStream is = jarFile.getInputStream(entry);
+ is.skip(100000);
+ is.close();
+ Certificate[] certs = entry.getCertificates();
+ if (certs != null && certs.length > 0) {
+ foundCerts = true;
+ break;
+ }
+ }
+ assertTrue(
+ "No certificates found during signed jar test for jar \""
+ + jarName + "\"", foundCerts);
+ } catch (IOException e) {
+ fail("Exception during signed jar test for jar \"" + jarName
+ + "\": " + e.toString());
+ }
+ }
+ }
+
/**
* @tests java.util.jar.JarFile#getManifest()
*/
@@ -540,85 +645,6 @@
}
/**
- * @throws IOException
- * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getInputStream",
- args = {java.util.zip.ZipEntry.class}
- )
- public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
- File localFile = null;
- try {
- Support_Resources.copyFile(resources, null, jarName);
- localFile = new File(resources, jarName);
- } catch (Exception e) {
- fail("Failed to create local file: " + e);
- }
-
- byte[] b = new byte[1024];
- try {
- JarFile jf = new JarFile(localFile);
- java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
- // BEGIN android-removed
- // jf.close();
- // END android-removed
- assertTrue("Returned invalid stream", is.available() > 0);
- int r = is.read(b, 0, 1024);
- is.close();
- StringBuffer sb = new StringBuffer(r);
- for (int i = 0; i < r; i++) {
- sb.append((char) (b[i] & 0xff));
- }
- String contents = sb.toString();
- assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
- // BEGIN android-added
- jf.close();
- // END android-added
- } catch (Exception e) {
- fail("Exception during test: " + e.toString());
- }
-
- try {
- JarFile jf = new JarFile(localFile);
- InputStream in = jf.getInputStream(new JarEntry("invalid"));
- assertNull("Got stream for non-existent entry", in);
- } catch (Exception e) {
- fail("Exception during test 2: " + e);
- }
-
- try {
- Support_Resources.copyFile(resources, null, jarName);
- File signedFile = new File(resources, jarName);
- JarFile jf = new JarFile(signedFile);
- JarEntry jre = new JarEntry("foo/bar/A.class");
- jf.getInputStream(jre);
- // InputStream returned in any way, exception can be thrown in case
- // of reading from this stream only.
- // fail("Should throw ZipException");
- } catch (ZipException ee) {
- // expected
- }
-
- try {
- Support_Resources.copyFile(resources, null, jarName);
- File signedFile = new File(resources, jarName);
- JarFile jf = new JarFile(signedFile);
- JarEntry jre = new JarEntry("foo/bar/A.class");
- jf.close();
- jf.getInputStream(jre);
- // InputStream returned in any way, exception can be thrown in case
- // of reading from this stream only.
- // The same for IOException
- fail("Should throw IllegalStateException");
- } catch (IllegalStateException ee) {
- // expected
- }
- }
-
- /**
* @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
*/
@TestTargetNew(
@@ -660,7 +686,7 @@
} catch (Exception e) {
fail("Exception during test 4: " + e);
}
-
+
try {
JarFile jar = new JarFile(signedFile);
JarEntry entry = new JarEntry(entryName3);
@@ -682,7 +708,7 @@
} catch (Exception e) {
fail("Failed to create local file 5: " + e);
}
-
+
try {
JarFile jar = new JarFile(signedFile);
JarEntry entry = new JarEntry(entryName3);
@@ -732,7 +758,37 @@
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
- jarFile.getInputStream(zipEntry);
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ }
+ }
+
+ /**
+ * The jar is intact, but the entry object is modified.
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "getInputStream",
+ args = {ZipEntry.class}
+ )
+ public void testJarVerificationModifiedEntry() throws IOException {
+ Support_Resources.copyFile(resources, null, integrateJar);
+ File f = new File(resources, integrateJar);
+
+ JarFile jarFile = new JarFile(f);
+ ZipEntry zipEntry = jarFile.getJarEntry(integrateJarEntry);
+ zipEntry.setSize(zipEntry.getSize() + 1);
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+
+ jarFile = new JarFile(f);
+ zipEntry = jarFile.getJarEntry(integrateJarEntry);
+ zipEntry.setSize(zipEntry.getSize() - 1);
+ try {
+ //jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ jarFile.getInputStream(zipEntry).read(new byte[5000], 0, 5000);
+ fail("SecurityException expected");
+ } catch (SecurityException e) {
+ // desired
}
}
@@ -781,7 +837,6 @@
Enumeration<JarEntry> entries = jarFile.entries();
int count = 0;
while (entries.hasMoreElements()) {
-
ZipEntry zipEntry = entries.nextElement();
jarFile.getInputStream(zipEntry);
count++;
@@ -818,7 +873,7 @@
while (in.available() > 0) {
in.read(buffer);
}
- fail("should throw Security Exception");
+ fail("SecurityException expected");
} catch (SecurityException e) {
// desired
}
@@ -827,7 +882,7 @@
/*
* In the Modified.jar, the main attributes of META-INF/MANIFEST.MF is
* tampered manually. Hence the RI 5.0 JarFile.getInputStream of any
- * JarEntry will throw security exception, but the apache harmony will not.
+ * JarEntry will throw security exception.
*/
@TestTargetNew(
level = TestLevel.PARTIAL_COMPLETE,
@@ -846,7 +901,7 @@
ZipEntry zipEntry = entries.nextElement();
try {
jarFile.getInputStream(zipEntry);
- fail("should throw Security Exception");
+ fail("SecurityException expected");
} catch (SecurityException e) {
// desired
}
@@ -927,4 +982,83 @@
// Can not check IOException
}
+
+ /**
+ * @throws IOException
+ * @tests java.util.jar.JarFile#getInputStream(java.util.zip.ZipEntry)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ public void test_getInputStreamLjava_util_jar_JarEntry() throws IOException {
+ File localFile = null;
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ localFile = new File(resources, jarName);
+ } catch (Exception e) {
+ fail("Failed to create local file: " + e);
+ }
+
+ byte[] b = new byte[1024];
+ try {
+ JarFile jf = new JarFile(localFile);
+ java.io.InputStream is = jf.getInputStream(jf.getEntry(entryName));
+ // BEGIN android-removed
+ // jf.close();
+ // END android-removed
+ assertTrue("Returned invalid stream", is.available() > 0);
+ int r = is.read(b, 0, 1024);
+ is.close();
+ StringBuffer sb = new StringBuffer(r);
+ for (int i = 0; i < r; i++) {
+ sb.append((char) (b[i] & 0xff));
+ }
+ String contents = sb.toString();
+ assertTrue("Incorrect stream read", contents.indexOf("bar") > 0);
+ // BEGIN android-added
+ jf.close();
+ // END android-added
+ } catch (Exception e) {
+ fail("Exception during test: " + e.toString());
+ }
+
+ try {
+ JarFile jf = new JarFile(localFile);
+ InputStream in = jf.getInputStream(new JarEntry("invalid"));
+ assertNull("Got stream for non-existent entry", in);
+ } catch (Exception e) {
+ fail("Exception during test 2: " + e);
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ File signedFile = new File(resources, jarName);
+ JarFile jf = new JarFile(signedFile);
+ JarEntry jre = new JarEntry("foo/bar/A.class");
+ jf.getInputStream(jre);
+ // InputStream returned in any way, exception can be thrown in case
+ // of reading from this stream only.
+ // fail("Should throw ZipException");
+ } catch (ZipException ee) {
+ // expected
+ }
+
+ try {
+ Support_Resources.copyFile(resources, null, jarName);
+ File signedFile = new File(resources, jarName);
+ JarFile jf = new JarFile(signedFile);
+ JarEntry jre = new JarEntry("foo/bar/A.class");
+ jf.close();
+ jf.getInputStream(jre);
+ // InputStream returned in any way, exception can be thrown in case
+ // of reading from this stream only.
+ // The same for IOException
+ fail("Should throw IllegalStateException");
+ } catch (IllegalStateException ee) {
+ // expected
+ }
+ }
}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
index e652137..acdad71 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarOutputStreamTest.java
@@ -48,7 +48,7 @@
method = "putNextEntry",
args = {java.util.zip.ZipEntry.class}
)
- public void test_putNextEntryLjava_util_zip_ZipEntry() {
+ public void test_putNextEntryLjava_util_zip_ZipEntry() throws Exception {
// testClass file`s actual extension is .class, since having .class
// extension files in source dir causes
// problems on eclipse, the extension is changed into .ser or it can be
@@ -76,35 +76,30 @@
File outputJar = null;
JarOutputStream jout = null;
- try {
- // open the output jarfile
- outputJar = File.createTempFile("hyts_", ".jar");
- jout = new JarOutputStream(new FileOutputStream(outputJar),
- newman);
- jout.putNextEntry(new JarEntry(entryName));
- } catch (Exception e) {
- fail("Error creating JarOutputStream: " + e);
- }
+ // open the output jarfile
+ outputJar = File.createTempFile("hyts_", ".jar");
+ jout = new JarOutputStream(new FileOutputStream(outputJar),
+ newman);
+ jout.putNextEntry(new JarEntry(entryName));
+
File resources = Support_Resources.createTempFolder();
- try {
- // read in the class file, and output it to the jar
- Support_Resources.copyFile(resources, null, testClass);
- URL jarURL = new URL((new File(resources, testClass)).toURL()
- .toString());
- InputStream jis = jarURL.openStream();
- byte[] bytes = new byte[1024];
- int len;
- while ((len = jis.read(bytes)) != -1) {
- jout.write(bytes, 0, len);
- }
+ // read in the class file, and output it to the jar
+ Support_Resources.copyFile(resources, null, testClass);
+ URL jarURL = new URL((new File(resources, testClass)).toURL()
+ .toString());
+ InputStream jis = jarURL.openStream();
- jout.flush();
- jout.close();
- jis.close();
- } catch (Exception e) {
- fail("Error writing JAR file for testing: " + e);
+ byte[] bytes = new byte[1024];
+ int len;
+ while ((len = jis.read(bytes)) != -1) {
+ jout.write(bytes, 0, len);
}
+
+ jout.flush();
+ jout.close();
+ jis.close();
+
String res = null;
// set up the VM parameters
String[] args = new String[2];
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
index 57e4744..42b2543 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/ManifestTest.java
@@ -14,12 +14,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
package org.apache.harmony.archive.tests.java.util.jar;
-import dalvik.annotation.TestTargetClass;
-import dalvik.annotation.TestTargets;
+import dalvik.annotation.KnownFailure;
import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
import dalvik.annotation.TestTargetNew;
import java.io.ByteArrayInputStream;
@@ -28,14 +27,15 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
import java.net.URL;
+import java.net.MalformedURLException;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import junit.framework.TestCase;
+
import tests.support.resource.Support_Resources;
@TestTargetClass(Manifest.class)
@@ -49,6 +49,10 @@
private Manifest m2;
+ private final String ATT_ENTRY_NAME = "HasAttributes.txt";
+
+ private final String MANIFEST_NAME = "manifest/hyts_MANIFEST.MF";
+
private File resources;
@Override
@@ -68,6 +72,19 @@
}
}
+ private Manifest getManifest(String fileName) {
+ try {
+ Support_Resources.copyFile(resources, null, fileName);
+ JarFile jarFile = new JarFile(new File(resources, fileName));
+ Manifest m = jarFile.getManifest();
+ jarFile.close();
+ return m;
+ } catch (Exception e) {
+ fail("Exception during setup: " + e.toString());
+ return null;
+ }
+ }
+
/**
* @tests java.util.jar.Manifest#Manifest()
*/
@@ -87,245 +104,29 @@
}
/**
- * @tests java.util.jar.Manifest#Manifest(java.io.InputStream)
+ * @tests java.util.jar.Manifest#Manifest(java.util.jar.Manifest)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "IOException checking missed.",
- method = "Manifest",
- args = {java.io.InputStream.class}
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {java.util.jar.Manifest.class}
)
- public void test_ConstructorLjava_io_InputStream() {
- // Test for method java.util.jar.Manifest(java.io.InputStream)
- /*
- * ByteArrayOutputStream baos = new ByteArrayOutputStream();
- * m2.write(baos); InputSteam is = new ByteArrayInputStream
- * (baos.toByteArray()); Manifest myManifest = new Manifest (is);
- * assertTrue("Manifests should be equal", myManifest.equals(m2));
- */
-
- Manifest manifest = null;
- InputStream is = null;
- try {
- is = new URL(Support_Resources.getURL("manifest/hyts_MANIFEST.MF"))
- .openStream();
- } catch (MalformedURLException e1) {
- fail("Failed to create InputStream object");
- } catch (IOException e1) {
- fail("Failed to create InputStream object");
- }
- try {
- manifest = new Manifest(is);
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
- Attributes main = manifest.getMainAttributes();
- assertEquals("Bundle-Name not correct", "ClientSupport", main
- .getValue("Bundle-Name"));
- assertEquals(
- "Bundle-Description not correct",
-
- "Provides SessionService, AuthenticationService. Extends RegistryService.",
- main.getValue("Bundle-Description"));
- assertEquals("Bundle-Activator not correct",
- "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
- main.getValue("Bundle-Activator"));
- assertEquals(
- "Import-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
- main.getValue("Import-Package"));
- assertEquals(
- "Import-Service not correct",
-
- "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
- main.getValue("Import-Service"));
- assertEquals(
- "Export-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
- main.getValue("Export-Package"));
- assertEquals(
- "Export-Service not correct",
-
- "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
- main.getValue("Export-Service"));
- assertEquals("Bundle-Vendor not correct", "IBM", main
- .getValue("Bundle-Vendor"));
- assertEquals("Bundle-Version not correct", "1.2.0", main
- .getValue("Bundle-Version"));
- try {
- is.close();
- } catch (IOException e1) {
- fail("Failed to close InputStream object");
- }
- try {
- manifest = new Manifest(is);
- fail("IOException expected");
- } catch (MalformedURLException e) {
- fail("IOException expected");
- } catch (IOException e) {
- // expected
- }
- }
-
- /**
- * @tests java.util.jar.Manifest#clear()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "clear",
- args = {}
- )
- public void test_clear() {
- // Test for method void java.util.jar.Manifest.clear()
- m2.clear();
- assertTrue("Should have no entries", m2.getEntries().isEmpty());
- assertTrue("Should have no main attributes", m2.getMainAttributes()
- .isEmpty());
- }
-
- /**
- * @tests java.util.jar.Manifest#getAttributes(java.lang.String)
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getAttributes",
- args = {java.lang.String.class}
- )
- public void test_getAttributesLjava_lang_String() {
- // Test for method java.util.jar.Attributes
- // java.util.jar.Manifest.getAttributes(java.lang.String)
- assertNull("Should not exist", m2.getAttributes("Doesn't Exist"));
- assertEquals("Should exist", "OK", m2
- .getAttributes("HasAttributes.txt").get(
- new Attributes.Name("MyAttribute")));
- }
-
- /**
- * @tests java.util.jar.Manifest#getEntries()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getEntries",
- args = {}
- )
- public void test_getEntries() {
- // Test for method java.util.Map java.util.jar.Manifest.getEntries()
- Map<String, Attributes> myMap = m2.getEntries();
- assertNull("Shouldn't exist", myMap.get("Doesn't exist"));
- assertEquals("Should exist", "OK", myMap.get("HasAttributes.txt").get(
- new Attributes.Name("MyAttribute")));
-
- }
-
- /**
- * @tests java.util.jar.Manifest#getMainAttributes()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "getMainAttributes",
- args = {}
- )
- public void test_getMainAttributes() {
- // Test for method java.util.jar.Attributes
- // java.util.jar.Manifest.getMainAttributes()
- Attributes a = m.getMainAttributes();
- assertEquals("Manifest_Version should return 1.0", "1.0", a
- .get(Attributes.Name.MANIFEST_VERSION));
- }
-
- /**
- * @tests {@link java.util.jar.Manifest#read(java.io.InputStream)
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "read",
- args = {java.io.InputStream.class}
- )
- public void test_readLjava_io_InputStream() {
- // Regression for HARMONY-89
- InputStream is = new InputStreamImpl();
- try {
- new Manifest().read(is);
- fail("Assert 0: Should have thrown IOException");
- } catch (IOException e) {
- // expected
- }
-
- Manifest manifest = new Manifest();
- try {
- manifest.read(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Can nor read manifest");
- } catch (IOException e) {
- fail("Can nor read manifest");
- }
- Attributes main = manifest.getMainAttributes();
- assertEquals("Bundle-Name not correct", "ClientSupport", main
- .getValue("Bundle-Name"));
- assertEquals(
- "Bundle-Description not correct",
-
- "Provides SessionService, AuthenticationService. Extends RegistryService.",
- main.getValue("Bundle-Description"));
- assertEquals("Bundle-Activator not correct",
- "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
- main.getValue("Bundle-Activator"));
- assertEquals(
- "Import-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
- main.getValue("Import-Package"));
- assertEquals(
- "Import-Service not correct",
-
- "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
- main.getValue("Import-Service"));
- assertEquals(
- "Export-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
- main.getValue("Export-Package"));
- assertEquals(
- "Export-Service not correct",
-
- "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
- main.getValue("Export-Service"));
- assertEquals("Bundle-Vendor not correct", "IBM", main
- .getValue("Bundle-Vendor"));
- assertEquals("Bundle-Version not correct", "1.2.0", main
- .getValue("Bundle-Version"));
- }
-
- // helper class
- class InputStreamImpl extends InputStream {
- public InputStreamImpl() {
- super();
- }
-
- @Override
- public int read() {
- return 0;
- }
+ public void testCopyingConstructor() throws IOException {
+ Manifest firstManifest = new Manifest(new URL(Support_Resources
+ .getURL(MANIFEST_NAME)).openStream());
+ Manifest secondManifest = new Manifest(firstManifest);
+ assertEquals(firstManifest, secondManifest);
}
/**
* @tests java.util.jar.Manifest#Manifest(Manifest)
*/
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "Manifest",
- args = {java.util.jar.Manifest.class}
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {java.util.jar.Manifest.class}
)
public void test_ConstructorLjava_util_jar_Manifest() {
// Test for method java.util.jar.Manifest()
@@ -338,13 +139,101 @@
assertEquals(emptyClone, emptyManifest.clone());
}
+ private void assertAttribute(Attributes attr, String name, String value) {
+ assertEquals("Incorrect " + name, value, attr.getValue(name));
+ }
+
+ private void checkManifest(Manifest manifest) {
+ Attributes main = manifest.getMainAttributes();
+ assertAttribute(main, "Bundle-Name", "ClientSupport");
+ assertAttribute(main, "Bundle-Description",
+ "Provides SessionService, AuthenticationService. Extends RegistryService.");
+ assertAttribute(main, "Bundle-Activator",
+ "com.ibm.ive.eccomm.client.support.ClientSupportActivator");
+ assertAttribute(
+ main,
+ "Import-Package",
+ "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client");
+ assertAttribute(
+ main,
+ "Import-Service",
+ "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService");
+ assertAttribute(
+ main,
+ "Export-Package",
+ "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0");
+ assertAttribute(
+ main,
+ "Export-Service",
+ "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService");
+ assertAttribute(main, "Bundle-Vendor", "IBM");
+ assertAttribute(main, "Bundle-Version", "1.2.0");
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#Manifest(java.io.InputStream)
+ */
@TestTargetNew(
level = TestLevel.COMPLETE,
- notes = "",
- method = "clone",
- args = {}
+ notes = "IOException checking missed.",
+ method = "Manifest",
+ args = {java.io.InputStream.class}
)
- public void test_clone() {
+ public void test_ConstructorLjava_io_InputStream() throws IOException {
+ Manifest m = getManifest(attJarName);
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ m.write(baos);
+ InputStream is = new ByteArrayInputStream(baos.toByteArray());
+ Manifest mCopy = new Manifest(is);
+ assertEquals(m, mCopy);
+
+ Manifest manifest = new Manifest(new URL(Support_Resources
+ .getURL(MANIFEST_NAME)).openStream());
+ checkManifest(manifest);
+
+ // regression test for HARMONY-5424
+ String manifestContent = "Manifest-Version: 1.0\nCreated-By: Apache\nPackage: \nBuild-Jdk: 1.4.1_01\n\n"
+ + "Name: \nSpecification-Title: foo\nSpecification-Version: 1.0\nSpecification-Vendor: \n"
+ + "Implementation-Title: \nImplementation-Version: 1.0\nImplementation-Vendor: \n\n";
+ ByteArrayInputStream bis = new ByteArrayInputStream(manifestContent
+ .getBytes("ISO-8859-1"));
+
+
+ Manifest mf = new Manifest(bis);
+ assertEquals("Should be 4 main attributes", 4, mf.getMainAttributes()
+ .size());
+
+ Map<String, Attributes> entries = mf.getEntries();
+ assertEquals("Should be one named entry", 1, entries.size());
+
+ Attributes namedEntryAttributes = (Attributes) (entries.get(""));
+ assertEquals("Should be 6 named entry attributes", 6,
+ namedEntryAttributes.size());
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#clear()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clear",
+ args = {}
+ )
+ public void test_clear() {
+ m2.clear();
+ assertTrue("Should have no entries", m2.getEntries().isEmpty());
+ assertTrue("Should have no main attributes", m2.getMainAttributes()
+ .isEmpty());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clone",
+ args = {}
+ )
+ public void test_clone() throws IOException {
Manifest emptyManifest = new Manifest();
Manifest emptyClone = (Manifest) emptyManifest.clone();
assertTrue("Should have no entries", emptyClone.getEntries().isEmpty());
@@ -354,88 +243,25 @@
assertEquals(emptyManifest.clone().getClass().getName(),
"java.util.jar.Manifest");
- Manifest manifest = null;
- try {
- manifest = new Manifest(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
+ Manifest manifest = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
Manifest manifestClone = (Manifest) manifest.clone();
- Attributes main = manifestClone.getMainAttributes();
- assertEquals("Bundle-Name not correct", "ClientSupport", main
- .getValue("Bundle-Name"));
- assertEquals(
- "Bundle-Description not correct",
-
- "Provides SessionService, AuthenticationService. Extends RegistryService.",
- main.getValue("Bundle-Description"));
- assertEquals("Bundle-Activator not correct",
- "com.ibm.ive.eccomm.client.support.ClientSupportActivator",
- main.getValue("Bundle-Activator"));
- assertEquals(
- "Import-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.log,com.ibm.ive.eccomm.client.services.registry,com.ibm.ive.eccomm.service.registry; specification-version=1.0.0,com.ibm.ive.eccomm.service.session; specification-version=1.0.0,com.ibm.ive.eccomm.service.framework; specification-version=1.2.0,org.osgi.framework; specification-version=1.0.0,org.osgi.service.log; specification-version=1.0.0,com.ibm.ive.eccomm.flash; specification-version=1.2.0,com.ibm.ive.eccomm.client.xml,com.ibm.ive.eccomm.client.http.common,com.ibm.ive.eccomm.client.http.client",
- main.getValue("Import-Package"));
- assertEquals(
- "Import-Service not correct",
-
- "org.osgi.service.log.LogReaderServiceorg.osgi.service.log.LogService,com.ibm.ive.eccomm.service.registry.RegistryService",
- main.getValue("Import-Service"));
- assertEquals(
- "Export-Package not correct",
-
- "com.ibm.ive.eccomm.client.services.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.service.authentication; specification-version=1.0.0,com.ibm.ive.eccomm.common; specification-version=1.0.0,com.ibm.ive.eccomm.client.services.registry.store; specification-version=1.0.0",
- main.getValue("Export-Package"));
- assertEquals(
- "Export-Service not correct",
-
- "com.ibm.ive.eccomm.service.authentication.AuthenticationService,com.ibm.ive.eccomm.service.session.SessionService",
- main.getValue("Export-Service"));
- assertEquals("Bundle-Vendor not correct", "IBM", main
- .getValue("Bundle-Vendor"));
- assertEquals("Bundle-Version not correct", "1.2.0", main
- .getValue("Bundle-Version"));
+ manifestClone.getMainAttributes();
+ checkManifest(manifestClone);
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "equals",
- args = {java.lang.Object.class}
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "equals",
+ args = {java.lang.Object.class}
)
- public void test_equals() {
- Manifest manifest1 = null;
- Manifest manifest2 = null;
+ public void test_equals() throws IOException {
+ Manifest manifest1 = new Manifest(new URL(Support_Resources.getURL(
+ "manifest/hyts_MANIFEST.MF")).openStream());
+ Manifest manifest2 = new Manifest(new URL(Support_Resources.getURL(
+ "manifest/hyts_MANIFEST.MF")).openStream());
Manifest manifest3 = new Manifest();
- InputStream is = null;
- try {
- is = new URL(Support_Resources.getURL("manifest/hyts_MANIFEST.MF"))
- .openStream();
- } catch (MalformedURLException e1) {
- fail("Failed to create InputStream object");
- } catch (IOException e1) {
- fail("Failed to create InputStream object");
- }
- try {
- manifest1 = new Manifest(is);
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
-
- try {
- manifest2 = new Manifest(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
assertTrue(manifest1.equals(manifest1));
assertTrue(manifest1.equals(manifest2));
@@ -444,27 +270,69 @@
}
@TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "hashCode",
- args = {}
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "hashCode",
+ args = {}
)
- public void test_hashCode() {
- Manifest manifest1 = null;
+ public void test_hashCode() throws IOException {
+ Manifest manifest1 = new Manifest(new URL(Support_Resources
+ .getURL("manifest/hyts_MANIFEST.MF")).openStream());
Manifest manifest2 = new Manifest();
- InputStream is = null;
- try {
- manifest1 = new Manifest(new URL(Support_Resources
- .getURL("manifest/hyts_MANIFEST.MF")).openStream());
- } catch (MalformedURLException e) {
- fail("Malformed URL");
- } catch (IOException e) {
- fail("IOException");
- }
assertEquals(manifest1.hashCode(), manifest1.hashCode());
assertNotSame(manifest1.hashCode(), manifest2.hashCode());
}
+ /**
+ * @tests java.util.jar.Manifest#getAttributes(java.lang.String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getAttributes",
+ args = {String.class}
+ )
+ public void test_getAttributesLjava_lang_String() {
+ assertNull("Should not exist",
+ m2.getAttributes("Doesn't Exist"));
+ assertEquals("Should exist", "OK", m2.getAttributes("HasAttributes.txt").get(
+ new Attributes.Name("MyAttribute")));
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getEntries()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getEntries",
+ args = {}
+ )
+ public void test_getEntries() {
+ Map<String, Attributes> myMap = m2.getEntries();
+ assertNull("Shouldn't exist", myMap.get("Doesn't exist"));
+ assertEquals("Should exist",
+ "OK", myMap.get("HasAttributes.txt").get(
+ new Attributes.Name("MyAttribute")));
+ }
+
+ /**
+ * @tests java.util.jar.Manifest#getMainAttributes()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getMainAttributes",
+ args = {}
+ )
+ public void test_getMainAttributes() {
+ // Test for method java.util.jar.Attributes
+ // java.util.jar.Manifest.getMainAttributes()
+ Attributes a = m.getMainAttributes();
+ assertEquals("Manifest_Version should return 1.0", "1.0", a.get(
+ Attributes.Name.MANIFEST_VERSION));
+ }
+
@TestTargetNew(
level = TestLevel.COMPLETE,
notes = "",
@@ -510,4 +378,219 @@
assertTrue(manifest1.equals(manifest2));
}
+
+ /**
+ * Ensures compatibility with manifests produced by gcc.
+ *
+ * @see <a
+ * href="http://issues.apache.org/jira/browse/HARMONY-5662">HARMONY-5662</a>
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "Manifest",
+ args = {InputStream.class}
+ )
+ public void testNul() throws IOException {
+ String manifestContent =
+ "Manifest-Version: 1.0\nCreated-By: nasty gcc tool\n\n\0";
+
+ byte[] bytes = manifestContent.getBytes("ISO-8859-1");
+ new Manifest(new ByteArrayInputStream(bytes)); // the last NUL is ok
+
+ bytes[bytes.length - 1] = 26;
+ new Manifest(new ByteArrayInputStream(bytes)); // the last EOF is ok
+
+ bytes[bytes.length - 1] = 'A'; // the last line ignored
+ new Manifest(new ByteArrayInputStream(bytes));
+
+ bytes[2] = 0; // NUL char in Manifest
+ try {
+ new Manifest(new ByteArrayInputStream(bytes));
+ fail("IOException expected");
+ } catch (IOException e) {
+ // desired
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "Manifest",
+ args = {InputStream.class}
+ )
+ @KnownFailure("CharsetDecoder fails with an IllegalStateException")
+ public void testDecoding() throws IOException {
+ Manifest m = getManifest(attJarName);
+ final byte[] bVendor = new byte[] { (byte) 0xd0, (byte) 0x9C,
+ (byte) 0xd0, (byte) 0xb8, (byte) 0xd0, (byte) 0xbb,
+ (byte) 0xd0, (byte) 0xb0, (byte) 0xd1, (byte) 0x8f, ' ',
+ (byte) 0xd0, (byte) 0xb4, (byte) 0xd0, (byte) 0xbe,
+ (byte) 0xd1, (byte) 0x87, (byte) 0xd1, (byte) 0x83,
+ (byte) 0xd0, (byte) 0xbd, (byte) 0xd1, (byte) 0x8C,
+ (byte) 0xd0, (byte) 0xba, (byte) 0xd0, (byte) 0xb0, ' ',
+ (byte) 0xd0, (byte) 0x9C, (byte) 0xd0, (byte) 0xb0,
+ (byte) 0xd1, (byte) 0x88, (byte) 0xd0, (byte) 0xb0 };
+
+ final byte[] bSpec = new byte[] { (byte) 0xe1, (byte) 0x88,
+ (byte) 0xb0, (byte) 0xe1, (byte) 0x88, (byte) 0x8b,
+ (byte) 0xe1, (byte) 0x88, (byte) 0x9d, ' ', (byte) 0xe1,
+ (byte) 0x9a, (byte) 0xa0, (byte) 0xe1, (byte) 0x9a,
+ (byte) 0xb1, (byte) 0xe1, (byte) 0x9b, (byte) 0x81,
+ (byte) 0xe1, (byte) 0x9a, (byte) 0xa6, ' ', (byte) 0xd8,
+ (byte) 0xb3, (byte) 0xd9, (byte) 0x84, (byte) 0xd8,
+ (byte) 0xa7, (byte) 0xd9, (byte) 0x85, ' ', (byte) 0xd8,
+ (byte) 0xb9, (byte) 0xd8, (byte) 0xb3, (byte) 0xd9,
+ (byte) 0x84, (byte) 0xd8, (byte) 0xa7, (byte) 0xd9,
+ (byte) 0x85, (byte) 0xd8, (byte) 0xa9, ' ', (byte) 0xdc,
+ (byte) 0xab, (byte) 0xdc, (byte) 0xa0, (byte) 0xdc,
+ (byte) 0xa1, (byte) 0xdc, (byte) 0x90, ' ', (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xb6, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbe, (byte) 0xe0, (byte) 0xa6, (byte) 0xa8,
+ (byte) 0xe0, (byte) 0xa7, (byte) 0x8d, (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xa4, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbf, ' ', (byte) 0xd0, (byte) 0xa0, (byte) 0xd0,
+ (byte) 0xb5, (byte) 0xd0, (byte) 0xba, (byte) 0xd1,
+ (byte) 0x8a, (byte) 0xd0, (byte) 0xb5, (byte) 0xd0,
+ (byte) 0xbb, ' ', (byte) 0xd0, (byte) 0x9c, (byte) 0xd0,
+ (byte) 0xb8, (byte) 0xd1, (byte) 0x80, ' ', (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xb6, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbe, (byte) 0xe0, (byte) 0xa6, (byte) 0xa8,
+ (byte) 0xe0, (byte) 0xa7, (byte) 0x8d, (byte) 0xe0,
+ (byte) 0xa6, (byte) 0xa4, (byte) 0xe0, (byte) 0xa6,
+ (byte) 0xbf, ' ', (byte) 0xe0, (byte) 0xbd, (byte) 0x9e,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xb2, (byte) 0xe0,
+ (byte) 0xbc, (byte) 0x8b, (byte) 0xe0, (byte) 0xbd,
+ (byte) 0x96, (byte) 0xe0, (byte) 0xbd, (byte) 0x91,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xba, ' ', (byte) 0xd0,
+ (byte) 0x9c, (byte) 0xd0, (byte) 0xb0, (byte) 0xd1,
+ (byte) 0x88, (byte) 0xd0, (byte) 0xb0, (byte) 0xd1,
+ (byte) 0x80, ' ', (byte) 0xe1, (byte) 0x8f, (byte) 0x99,
+ (byte) 0xe1, (byte) 0x8e, (byte) 0xaf, (byte) 0xe1,
+ (byte) 0x8f, (byte) 0xb1, ' ', (byte) 0xcf, (byte) 0xa8,
+ (byte) 0xce, (byte) 0xb9, (byte) 0xcf, (byte) 0x81,
+ (byte) 0xce, (byte) 0xb7, (byte) 0xce, (byte) 0xbd,
+ (byte) 0xce, (byte) 0xb7, ' ', (byte) 0xde, (byte) 0x90,
+ (byte) 0xde, (byte) 0xaa, (byte) 0xde, (byte) 0x85,
+ (byte) 0xde, (byte) 0xa6, ' ', (byte) 0xe0, (byte) 0xbd,
+ (byte) 0x82, (byte) 0xe0, (byte) 0xbd, (byte) 0x9e,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xb2, (byte) 0xe0,
+ (byte) 0xbc, (byte) 0x8b, (byte) 0xe0, (byte) 0xbd,
+ (byte) 0x96, (byte) 0xe0, (byte) 0xbd, (byte) 0x91,
+ (byte) 0xe0, (byte) 0xbd, (byte) 0xba, ' ', (byte) 0xce,
+ (byte) 0x95, (byte) 0xce, (byte) 0xb9, (byte) 0xcf,
+ (byte) 0x81, (byte) 0xce, (byte) 0xae, (byte) 0xce,
+ (byte) 0xbd, (byte) 0xce, (byte) 0xb7, ' ', (byte) 0xd8,
+ (byte) 0xb5, (byte) 0xd9, (byte) 0x84, (byte) 0xd8,
+ (byte) 0xad, ' ', (byte) 0xe0, (byte) 0xaa, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0xaa, (byte) 0xbe, (byte) 0xe0,
+ (byte) 0xaa, (byte) 0x82, (byte) 0xe0, (byte) 0xaa,
+ (byte) 0xa4, (byte) 0xe0, (byte) 0xaa, (byte) 0xbf, ' ',
+ (byte) 0xe5, (byte) 0xb9, (byte) 0xb3, (byte) 0xe5,
+ (byte) 0x92, (byte) 0x8c, ' ', (byte) 0xd7, (byte) 0xa9,
+ (byte) 0xd7, (byte) 0x9c, (byte) 0xd7, (byte) 0x95,
+ (byte) 0xd7, (byte) 0x9d, ' ', (byte) 0xd7, (byte) 0xa4,
+ (byte) 0xd7, (byte) 0xa8, (byte) 0xd7, (byte) 0x99,
+ (byte) 0xd7, (byte) 0x93, (byte) 0xd7, (byte) 0x9f, ' ',
+ (byte) 0xe5, (byte) 0x92, (byte) 0x8c, (byte) 0xe5,
+ (byte) 0xb9, (byte) 0xb3, ' ', (byte) 0xe5, (byte) 0x92,
+ (byte) 0x8c, (byte) 0xe5, (byte) 0xb9, (byte) 0xb3, ' ',
+ (byte) 0xd8, (byte) 0xaa, (byte) 0xd9, (byte) 0x89,
+ (byte) 0xd9, (byte) 0x86, (byte) 0xda, (byte) 0x86,
+ (byte) 0xd9, (byte) 0x84, (byte) 0xd9, (byte) 0x89,
+ (byte) 0xd9, (byte) 0x82, ' ', (byte) 0xe0, (byte) 0xae,
+ (byte) 0x85, (byte) 0xe0, (byte) 0xae, (byte) 0xae,
+ (byte) 0xe0, (byte) 0xaf, (byte) 0x88, (byte) 0xe0,
+ (byte) 0xae, (byte) 0xa4, (byte) 0xe0, (byte) 0xae,
+ (byte) 0xbf, ' ', (byte) 0xe0, (byte) 0xb0, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0xb0, (byte) 0xbe, (byte) 0xe0,
+ (byte) 0xb0, (byte) 0x82, (byte) 0xe0, (byte) 0xb0,
+ (byte) 0xa4, (byte) 0xe0, (byte) 0xb0, (byte) 0xbf, ' ',
+ (byte) 0xe0, (byte) 0xb8, (byte) 0xaa, (byte) 0xe0,
+ (byte) 0xb8, (byte) 0xb1, (byte) 0xe0, (byte) 0xb8,
+ (byte) 0x99, (byte) 0xe0, (byte) 0xb8, (byte) 0x95,
+ (byte) 0xe0, (byte) 0xb8, (byte) 0xb4, (byte) 0xe0,
+ (byte) 0xb8, (byte) 0xa0, (byte) 0xe0, (byte) 0xb8,
+ (byte) 0xb2, (byte) 0xe0, (byte) 0xb8, (byte) 0x9e, ' ',
+ (byte) 0xe1, (byte) 0x88, (byte) 0xb0, (byte) 0xe1,
+ (byte) 0x88, (byte) 0x8b, (byte) 0xe1, (byte) 0x88,
+ (byte) 0x9d, ' ', (byte) 0xe0, (byte) 0xb7, (byte) 0x83,
+ (byte) 0xe0, (byte) 0xb7, (byte) 0x8f, (byte) 0xe0,
+ (byte) 0xb6, (byte) 0xb8, (byte) 0xe0, (byte) 0xb6,
+ (byte) 0xba, ' ', (byte) 0xe0, (byte) 0xa4, (byte) 0xb6,
+ (byte) 0xe0, (byte) 0xa4, (byte) 0xbe, (byte) 0xe0,
+ (byte) 0xa4, (byte) 0xa8, (byte) 0xe0, (byte) 0xa5,
+ (byte) 0x8d, (byte) 0xe0, (byte) 0xa4, (byte) 0xa4,
+ (byte) 0xe0, (byte) 0xa4, (byte) 0xbf, (byte) 0xe0,
+ (byte) 0xa4, (byte) 0x83, ' ', (byte) 0xe1, (byte) 0x83,
+ (byte) 0x9b, (byte) 0xe1, (byte) 0x83, (byte) 0xa8,
+ (byte) 0xe1, (byte) 0x83, (byte) 0x95, (byte) 0xe1,
+ (byte) 0x83, (byte) 0x98, (byte) 0xe1, (byte) 0x83,
+ (byte) 0x93, (byte) 0xe1, (byte) 0x83, (byte) 0x9d,
+ (byte) 0xe1, (byte) 0x83, (byte) 0x91, (byte) 0xe1,
+ (byte) 0x83, (byte) 0x90 };
+ // TODO Cannot make the following word work, encoder changes needed
+ // (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbc, (byte) 0xb2, (byte) 0xed,
+ // (byte) 0xa0, (byte) 0x80, (byte) 0xed, (byte) 0xbc,
+ // (byte) 0xb0, (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbd, (byte) 0x85, (byte) 0xed,
+ // (byte) 0xa0, (byte) 0x80, (byte) 0xed, (byte) 0xbc,
+ // (byte) 0xb0, (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbc, (byte) 0xb9, (byte) 0xed,
+ // (byte) 0xa0, (byte) 0x80, (byte) 0xed, (byte) 0xbc,
+ // (byte) 0xb8, (byte) 0xed, (byte) 0xa0, (byte) 0x80,
+ // (byte) 0xed, (byte) 0xbc, (byte) 0xb9, ' '
+
+ final String vendor = new String(bVendor, "UTF-8");
+ final String spec = new String(bSpec, "UTF-8");
+ m.getMainAttributes()
+ .put(Attributes.Name.IMPLEMENTATION_VENDOR, vendor);
+ m.getAttributes(ATT_ENTRY_NAME).put(
+ Attributes.Name.IMPLEMENTATION_VENDOR, vendor);
+ m.getEntries().get(ATT_ENTRY_NAME).put(
+ Attributes.Name.SPECIFICATION_TITLE, spec);
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ m.write(baos);
+ m = new Manifest(new ByteArrayInputStream(baos.toByteArray()));
+
+ assertEquals(vendor, m.getMainAttributes().get(
+ Attributes.Name.IMPLEMENTATION_VENDOR));
+ assertEquals(vendor, m.getEntries().get(ATT_ENTRY_NAME).get(
+ Attributes.Name.IMPLEMENTATION_VENDOR));
+ assertEquals(spec, m.getAttributes(ATT_ENTRY_NAME).get(
+ Attributes.Name.SPECIFICATION_TITLE));
+ }
+
+ /**
+ * @tests {@link java.util.jar.Manifest#read(java.io.InputStream)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "",
+ method = "read",
+ args = {InputStream.class}
+ )
+ public void testRead() {
+ // Regression for HARMONY-89
+ InputStream is = new InputStreamImpl();
+ try {
+ new Manifest().read(is);
+ fail("IOException expected");
+ } catch (IOException e) {
+ // desired
+ }
+ }
+
+ // helper class
+ private class InputStreamImpl extends InputStream {
+ public InputStreamImpl() {
+ super();
+ }
+
+ @Override
+ public int read() {
+ return 0;
+ }
+ }
}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
index 75060bd..1e8ddb4 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPInputStreamTest.java
@@ -25,6 +25,8 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -310,7 +312,43 @@
}
}
- @Override
+ /**
+ * Regression test for HARMONY-3703.
+ * @tests java.util.zip.GZIPInputStream#read()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "read",
+ args = {byte[].class}
+ )
+ public void test_read() throws IOException {
+ GZIPInputStream gis = null;
+ int result = 0;
+ byte[] buffer = new byte[] {1,2,3,4,5,6,7,8,9,10};
+ File f = new File(resources.getAbsolutePath() + "test.gz");
+ FileOutputStream out = new FileOutputStream(f);
+ GZIPOutputStream gout = new GZIPOutputStream(out);
+
+ // write 100 bytes to the stream
+ for(int i = 0; i < 10; i++) {
+ gout.write(buffer);
+ }
+ gout.finish();
+ out.write(1);
+ out.close();
+
+ gis = new GZIPInputStream(new FileInputStream(f));
+ buffer = new byte[100];
+ gis.read(buffer);
+ result = gis.read();
+ gis.close();
+ f.delete();
+
+ assertEquals("Incorrect value returned at the end of the file", -1, result);
+ }
+
+ @Override
protected void setUp() {
resources = Support_Resources.createTempFolder();
}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
index 9b23b56..b71ce63 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/GZIPOutputStreamTest.java
@@ -201,8 +201,6 @@
int r = 0;
try {
outGZIP.write(byteArray, 0, 11);
- } catch (ArrayIndexOutOfBoundsException e) {
- r = 1;
} catch (IndexOutOfBoundsException ee) {
r = 1;
}
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
index 8b89180..6039c5b 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/InflaterTest.java
@@ -409,6 +409,22 @@
}
/**
+ * @tests java.util.zip.Inflater#Inflater()
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Inflater",
+ args = {}
+ )
+ public void test_Constructor() {
+ // test method of java.util.zip.inflater.Inflater()
+ Inflater inflate = new Inflater();
+ assertNotNull("failed to create the instance of inflater",
+ inflate);
+ }
+
+ /**
* @tests java.util.zip.Inflater#inflate(byte[], int, int)
*/
@TestTargetNew(
@@ -504,27 +520,6 @@
}
/**
- * @tests java.util.zip.Inflater#Inflater()
- */
- @TestTargetNew(
- level = TestLevel.COMPLETE,
- notes = "",
- method = "Inflater",
- args = {}
- )
- public void test_Constructor() {
- // test method of java.util.zip.inflater.Inflater()
- try {
- Inflater inflate = new Inflater();
- assertNotNull("failed to create the instance of inflater", inflate);
-
- } catch (Exception e) {
-
- assertTrue("Inflate () constructor threw an exception", true);
- }
- }
-
- /**
* @tests java.util.zip.Inflater#Inflater(boolean)
*/
@TestTargetNew(
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
index 5530a2e..c9e7bb8 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipFileTest.java
@@ -67,7 +67,7 @@
public void checkPermission(Permission perm) {
// only check if it's a FilePermission because Locale checks
// for a PropertyPermission with action"read" to get system props.
- if (perm instanceof FilePermission
+ if (perm instanceof FilePermission
&& perm.getActions().equals(forbidenPermissionAction)) {
throw new SecurityException();
}
@@ -145,7 +145,7 @@
public void test_ConstructorLjava_lang_String() throws IOException {
String oldUserDir = System.getProperty("user.dir");
System.setProperty("user.dir", System.getProperty("java.io.tmpdir"));
-
+
zfile.close(); // about to reopen the same temp file
ZipFile zip = new ZipFile(tempFileName);
zip.close();
@@ -260,7 +260,7 @@
method = "entries",
args = {}
)
- public void test_entries() {
+ public void test_entries() throws Exception {
// Test for method java.util.Enumeration java.util.zip.ZipFile.entries()
Enumeration<? extends ZipEntry> enumer = zfile.entries();
int c = 0;
@@ -270,20 +270,16 @@
}
assertTrue("Incorrect number of entries returned: " + c, c == 6);
+ Enumeration<? extends ZipEntry> enumeration = zfile.entries();
+ zfile.close();
+ zfile = null;
+ boolean pass = false;
try {
- Enumeration<? extends ZipEntry> enumeration = zfile.entries();
- zfile.close();
- zfile = null;
- boolean pass = false;
- try {
- enumeration.hasMoreElements();
- } catch (IllegalStateException e) {
- pass = true;
- }
- assertTrue("did not detect closed jar file", pass);
- } catch (Exception e) {
- fail("Exception during entries test: " + e.toString());
+ enumeration.hasMoreElements();
+ } catch (IllegalStateException e) {
+ pass = true;
}
+ assertTrue("did not detect closed jar file", pass);
}
/**
@@ -454,6 +450,99 @@
}
/**
+ * @tests java.io.InputStream#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @KnownFailure("ZipEntry.getInputStream().reset() fails with an IOException")
+ public void test_reset() throws IOException {
+ // read an uncompressed entry
+ ZipEntry zentry = zfile.getEntry("File1.txt");
+ InputStream is = zfile.getInputStream(zentry);
+ byte[] rbuf1 = new byte[6];
+ byte[] rbuf2 = new byte[6];
+ int r1, r2;
+ r1 = is.read(rbuf1);
+ assertEquals(rbuf1.length, r1);
+ r2 = is.read(rbuf2);
+ assertEquals(rbuf2.length, r2);
+
+ is.reset();
+ r2 = is.read(rbuf2);
+ assertEquals(rbuf2.length, r2);
+ is.close();
+
+ // read a compressed entry
+ byte[] rbuf3 = new byte[4185];
+ ZipEntry zentry2 = zfile.getEntry("File3.txt");
+ is = zfile.getInputStream(zentry2);
+ r1 = is.read(rbuf3);
+ assertEquals(4183, r1);
+ is.reset();
+
+ r1 = is.read(rbuf3);
+ assertEquals(4183, r1);
+ is.close();
+
+ is = zfile.getInputStream(zentry2);
+ r1 = is.read(rbuf3, 0, 3000);
+ assertEquals(3000, r1);
+ is.reset();
+ r1 = is.read(rbuf3, 0, 3000);
+ assertEquals(3000, r1);
+ is.close();
+ }
+
+ /**
+ * @tests java.io.InputStream#reset()
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ method = "getInputStream",
+ args = {java.util.zip.ZipEntry.class}
+ )
+ @KnownFailure("ZipEntry.getInputStream().reset() fails with an IOException")
+ public void test_reset_subtest0() throws IOException {
+ // read an uncompressed entry
+ ZipEntry zentry = zfile.getEntry("File1.txt");
+ InputStream is = zfile.getInputStream(zentry);
+ byte[] rbuf1 = new byte[12];
+ byte[] rbuf2 = new byte[12];
+ int r = is.read(rbuf1, 0, 4);
+ assertEquals(4, r);
+ is.mark(0);
+ r = is.read(rbuf1);
+ assertEquals(8, r);
+ assertEquals(-1, is.read());
+
+ is.reset();
+ r = is.read(rbuf2);
+ assertEquals(8, r);
+ assertEquals(-1, is.read());
+ is.close();
+
+ // read a compressed entry
+ byte[] rbuf3 = new byte[4185];
+ ZipEntry zentry2 = zfile.getEntry("File3.txt");
+ is = zfile.getInputStream(zentry2);
+ r = is.read(rbuf3, 0, 3000);
+ assertEquals(3000, r);
+ is.mark(0);
+ r = is.read(rbuf3);
+ assertEquals(1183, r);
+ assertEquals(-1, is.read());
+
+ is.reset();
+ r = is.read(rbuf3);
+ assertEquals(1183, r);
+ assertEquals(-1, is.read());
+ is.close();
+ }
+
+ /**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
diff --git a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
index 9a5f63a..8ca551d 100644
--- a/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
+++ b/libcore/archive/src/test/java/org/apache/harmony/archive/tests/java/util/zip/ZipOutputStreamTest.java
@@ -170,11 +170,8 @@
public void test_setCommentLjava_lang_String() {
// There is no way to get the comment back, so no way to determine if
// the comment is set correct
- try {
- zos.setComment("test setComment");
- } catch (Exception e) {
- fail("Trying to set comment failed");
- }
+ zos.setComment("test setComment");
+
try {
zos.setComment(new String(new byte[0xFFFF + 1]));
fail("Comment over 0xFFFF in length should throw exception");
@@ -301,6 +298,17 @@
} catch (IndexOutOfBoundsException e) {
// expected
}
+
+ // Regression for HARMONY-4405
+ try {
+ zip.write(null, 0, -2);
+ fail("Should throw IndexOutOfBoundsException");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // Close stream because ZIP is invalid
+ stream.close();
}
/**
@@ -337,6 +345,8 @@
} catch (IOException e2) {
// expected
}
+
+ zip1.close();
}
@Override
diff --git a/libcore/auth/src/main/java/javax/security/auth/AuthPermission.java b/libcore/auth/src/main/java/javax/security/auth/AuthPermission.java
index 06ea3fb..697d5c7 100644
--- a/libcore/auth/src/main/java/javax/security/auth/AuthPermission.java
+++ b/libcore/auth/src/main/java/javax/security/auth/AuthPermission.java
@@ -26,33 +26,31 @@
* <i>target name</i> of the permission specifies which methods are allowed
* without specifying the concrete action lists. Possible target names and
* associated authentication permissions are:
- *
+ *
* <pre>
* doAs invoke Subject.doAs methods.
* doAsPrivileged invoke the Subject.doAsPrivileged methods.
* getSubject invoke Subject.getSubject().
* getSubjectFromDomainCombiner invoke SubjectDomainCombiner.getSubject().
* setReadOnly invoke Subject.setReadonly().
- * modifyPrincipals modify the set of principals
+ * modifyPrincipals modify the set of principals
* associated with a Subject.
* modifyPublicCredentials modify the set of public credentials
* associated with a Subject.
* modifyPrivateCredentials modify the set of private credentials
* associated with a Subject.
- * refreshCredential invoke the refresh method on a credential of a
+ * refreshCredential invoke the refresh method on a credential of a
* refreshable credential class.
* destroyCredential invoke the destroy method on a credential of a
* destroyable credential class.
* createLoginContext.<i>name</i> instantiate a LoginContext with the
* specified name. The wildcard name ('*')
* allows to a LoginContext of any name.
- * getLoginConfiguration invoke the getConfiguration method of
+ * getLoginConfiguration invoke the getConfiguration method of
* javax.security.auth.login.Configuration.
- * refreshLoginConfiguration Invoke the refresh method of
+ * refreshLoginConfiguration Invoke the refresh method of
* javax.security.auth.login.Configuration.
* </pre>
- *
- * @since Android 1.0
*/
public final class AuthPermission extends BasicPermission {
@@ -77,7 +75,7 @@
/**
* Creates an authentication permission with the specified target name.
- *
+ *
* @param name
* the target name of this authentication permission.
*/
@@ -87,7 +85,7 @@
/**
* Creates an authentication permission with the specified target name.
- *
+ *
* @param name
* the target name of this authentication permission.
* @param actions
diff --git a/libcore/auth/src/main/java/javax/security/auth/DestroyFailedException.java b/libcore/auth/src/main/java/javax/security/auth/DestroyFailedException.java
index a5438a6..27d4dfd 100644
--- a/libcore/auth/src/main/java/javax/security/auth/DestroyFailedException.java
+++ b/libcore/auth/src/main/java/javax/security/auth/DestroyFailedException.java
@@ -19,8 +19,6 @@
/**
* Signals that the {@link Destroyable#destroy()} method failed.
- *
- * @since Android 1.0
*/
public class DestroyFailedException extends Exception {
@@ -35,7 +33,7 @@
/**
* Creates an exception of type {@code DestroyFailedException}.
- *
+ *
* @param message
* A detail message that describes the reason for this exception.
*/
diff --git a/libcore/auth/src/main/java/javax/security/auth/Destroyable.java b/libcore/auth/src/main/java/javax/security/auth/Destroyable.java
index 6194db6..b4d0fa2 100644
--- a/libcore/auth/src/main/java/javax/security/auth/Destroyable.java
+++ b/libcore/auth/src/main/java/javax/security/auth/Destroyable.java
@@ -20,8 +20,6 @@
/**
* Allows for special treatment of sensitive information, when it comes to
* destroying or clearing of the data.
- *
- * @since Android 1.0
*/
public interface Destroyable {
@@ -29,7 +27,7 @@
* Erases the sensitive information. Once an object is destroyed any calls
* to its methods will throw an {@code IllegalStateException}. If it does
* not succeed a DestroyFailedException is thrown.
- *
+ *
* @throws DestroyFailedException
* if the information cannot be erased.
*/
@@ -37,7 +35,7 @@
/**
* Returns {@code true} once an object has been safely destroyed.
- *
+ *
* @return whether the object has been safely destroyed.
*/
boolean isDestroyed();
diff --git a/libcore/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java b/libcore/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java
index d92ede5..35072b8 100644
--- a/libcore/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java
+++ b/libcore/auth/src/main/java/javax/security/auth/PrivateCredentialPermission.java
@@ -31,11 +31,11 @@
* Protects private credential objects belonging to a {@code Subject}. It has
* only one action which is "read". The target name of this permission has a
* special syntax:
- *
+ *
* <pre>
* targetName = CredentialClass {PrincipalClass "PrincipalName"}*
* </pre>
- *
+ *
* First it states a credential class and is followed then by a list of one or
* more principals identifying the subject.
* <p>
@@ -43,12 +43,11 @@
* Principal} class followed by the principal name in quotes. For example, the
* following file may define permission to read the private credentials of a
* principal named "Bob": "com.sun.PrivateCredential com.sun.Principal \"Bob\""
- * </p>
+ * <p>
* The syntax also allows the use of the wildcard "*" in place of {@code
* CredentialClass} or {@code PrincipalClass} and/or {@code PrincipalName}.
- *
+ *
* @see Principal
- * @since Android 1.0
*/
public final class PrivateCredentialPermission extends Permission {
@@ -69,7 +68,7 @@
* Creates a new permission for private credentials specified by the target
* name {@code name} and an {@code action}. The action is always
* {@code "read"}.
- *
+ *
* @param name
* the target name of the permission.
* @param action
@@ -197,13 +196,13 @@
* dimension of the array corresponds to the number of principals. The
* second dimension defines either the name of the {@code PrincipalClass}
* [x][0] or the value of {@code PrincipalName} [x][1].
- *
+ * <p>
* This corresponds to the the target name's syntax:
- *
+ *
* <pre>
* targetName = CredentialClass {PrincipalClass "PrincipalName"}*
* </pre>
- *
+ *
* @return the principal classes and names associated with this {@code
* PrivateCredentialPermission}.
*/
@@ -225,7 +224,7 @@
/**
* Returns the class name of the credential associated with this permission.
- *
+ *
* @return the class name of the credential associated with this permission.
*/
public String getCredentialClass() {
diff --git a/libcore/auth/src/main/java/javax/security/auth/Subject.java b/libcore/auth/src/main/java/javax/security/auth/Subject.java
index 5a4cceb..5bf6bba 100644
--- a/libcore/auth/src/main/java/javax/security/auth/Subject.java
+++ b/libcore/auth/src/main/java/javax/security/auth/Subject.java
@@ -51,8 +51,6 @@
* <li>Credentials (public and private) such as certificates, keys, or
* authentication proofs such as tickets</li>
* </ul>
- * </p>
- * @since Android 1.0
*/
public final class Subject implements Serializable {
@@ -104,7 +102,7 @@
/**
* The constructor for the subject, setting its public and private
* credentials and principals according to the arguments.
- *
+ *
* @param readOnly
* {@code true} if this {@code Subject} is read-only, thus
* preventing any modifications to be done.
@@ -135,7 +133,7 @@
/**
* Runs the code defined by {@code action} using the permissions granted to
* the {@code Subject} itself and to the code as well.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -154,7 +152,7 @@
* Run the code defined by {@code action} using the permissions granted to
* the {@code Subject} and to the code itself, additionally providing a more
* specific context.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -209,7 +207,7 @@
/**
* Runs the code defined by {@code action} using the permissions granted to
* the subject and to the code itself.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -231,7 +229,7 @@
* Runs the code defined by {@code action} using the permissions granted to
* the subject and to the code itself, additionally providing a more
* specific context.
- *
+ *
* @param subject
* the distinguished {@code Subject}.
* @param action
@@ -290,7 +288,7 @@
* Checks two Subjects for equality. More specifically if the principals,
* public and private credentials are equal, equality for two {@code
* Subjects} is implied.
- *
+ *
* @param obj
* the {@code Object} checked for equality with this {@code
* Subject}.
@@ -320,18 +318,18 @@
/**
* Returns this {@code Subject}'s {@link Principal}.
- *
+ *
* @return this {@code Subject}'s {@link Principal}.
*/
public Set<Principal> getPrincipals() {
return principals;
}
-
+
/**
* Returns this {@code Subject}'s {@link Principal} which is a subclass of
* the {@code Class} provided.
- *
+ *
* @param c
* the {@code Class} as a criteria which the {@code Principal}
* returned must satisfy.
@@ -345,7 +343,7 @@
/**
* Returns the private credentials associated with this {@code Subject}.
- *
+ *
* @return the private credentials associated with this {@code Subject}.
*/
public Set<Object> getPrivateCredentials() {
@@ -355,7 +353,7 @@
/**
* Returns this {@code Subject}'s private credentials which are a subclass
* of the {@code Class} provided.
- *
+ *
* @param c
* the {@code Class} as a criteria which the private credentials
* returned must satisfy.
@@ -369,18 +367,18 @@
/**
* Returns the public credentials associated with this {@code Subject}.
- *
+ *
* @return the public credentials associated with this {@code Subject}.
*/
public Set<Object> getPublicCredentials() {
return publicCredentials;
}
-
+
/**
* Returns this {@code Subject}'s public credentials which are a subclass of
* the {@code Class} provided.
- *
+ *
* @param c
* the {@code Class} as a criteria which the public credentials
* returned must satisfy.
@@ -394,7 +392,7 @@
/**
* Returns a hash code of this {@code Subject}.
- *
+ *
* @return a hash code of this {@code Subject}.
*/
@Override
@@ -417,7 +415,7 @@
/**
* Returns whether this {@code Subject} is read-only or not.
- *
+ *
* @return whether this {@code Subject} is read-only or not.
*/
public boolean isReadOnly() {
@@ -426,7 +424,7 @@
/**
* Returns a {@code String} representation of this {@code Subject}.
- *
+ *
* @return a {@code String} representation of this {@code Subject}.
*/
@Override
@@ -479,7 +477,7 @@
/**
* Returns the {@code Subject} that was last associated with the {@code
* context} provided as argument.
- *
+ *
* @param context
* the {@code context} that was associated with the
* {@code Subject}.
@@ -781,4 +779,4 @@
}
}
}
-}
+}
\ No newline at end of file
diff --git a/libcore/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java b/libcore/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java
index 6a8f00b..4b91084 100644
--- a/libcore/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java
+++ b/libcore/auth/src/main/java/javax/security/auth/SubjectDomainCombiner.java
@@ -25,8 +25,6 @@
/**
* Merges permissions based on code source and code signers with permissions
* granted to the specified {@link Subject}.
- *
- * @since Android 1.0
*/
public class SubjectDomainCombiner implements DomainCombiner {
@@ -39,7 +37,7 @@
/**
* Creates a domain combiner for the entity provided in {@code subject}.
- *
+ *
* @param subject
* the entity to which this domain combiner is associated.
*/
@@ -53,7 +51,7 @@
/**
* Returns the entity to which this domain combiner is associated.
- *
+ *
* @return the entity to which this domain combiner is associated.
*/
public Subject getSubject() {
@@ -68,7 +66,7 @@
/**
* Merges the {@code ProtectionDomain} with the {@code Principal}s
* associated with the subject of this {@code SubjectDomainCombiner}.
- *
+ *
* @param currentDomains
* the {@code ProtectionDomain}s associated with the context of
* the current thread. The domains must be sorted according to
diff --git a/libcore/auth/src/main/java/javax/security/auth/callback/Callback.java b/libcore/auth/src/main/java/javax/security/auth/callback/Callback.java
index 6cf46b8..4854d3f 100644
--- a/libcore/auth/src/main/java/javax/security/auth/callback/Callback.java
+++ b/libcore/auth/src/main/java/javax/security/auth/callback/Callback.java
@@ -20,8 +20,6 @@
/**
* Defines an empty base interface for all {@code Callback}s used during
* authentication.
- *
- * @since Android 1.0
*/
public interface Callback {
}
\ No newline at end of file
diff --git a/libcore/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java b/libcore/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java
index 952b81a..21bf30b 100644
--- a/libcore/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java
+++ b/libcore/auth/src/main/java/javax/security/auth/callback/CallbackHandler.java
@@ -27,8 +27,6 @@
* also possible to configure a system-default {@code CallbackHandler} by
* setting the {@code auth.login.defaultCallbackHandler} property in the
* standard {@code security.properties} file.
- *
- * @since Android 1.0
*/
public interface CallbackHandler {
@@ -42,7 +40,7 @@
* values. If a {@code CallbackHandler} is not able to handle a specific
* {@code Callback}, it needs to throw an
* {@link UnsupportedCallbackException}.
- *
+ *
* @param callbacks
* the array of {@code Callback}s that need handling
* @throws IOException
diff --git a/libcore/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java b/libcore/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java
index 00020fe..3617b75 100644
--- a/libcore/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java
+++ b/libcore/auth/src/main/java/javax/security/auth/callback/PasswordCallback.java
@@ -25,8 +25,6 @@
/**
* Is used in conjunction with a {@link CallbackHandler} to retrieve a password
* when needed.
- *
- * @since Android 1.0
*/
public class PasswordCallback implements Callback, Serializable {
@@ -47,7 +45,7 @@
/**
* Creates a new {@code PasswordCallback} instance.
- *
+ *
* @param prompt
* the message that should be displayed to the user
* @param echoOn
@@ -62,7 +60,7 @@
/**
* Returns the prompt that was specified when creating this {@code
* PasswordCallback}
- *
+ *
* @return the prompt
*/
public String getPrompt() {
@@ -72,7 +70,7 @@
/**
* Queries whether this {@code PasswordCallback} expects user input to be
* echoed, which is specified during the creation of the object.
- *
+ *
* @return {@code true} if (and only if) user input should be echoed
*/
public boolean isEchoOn() {
@@ -83,7 +81,7 @@
* Sets the password. The {@link CallbackHandler} that performs the actual
* provisioning or input of the password needs to call this method to hand
* back the password to the security service that requested it.
- *
+ *
* @param password
* the password. A copy of this is stored, so subsequent changes
* to the input array do not affect the {@code PasswordCallback}.
@@ -101,7 +99,7 @@
* Returns the password. The security service that needs the password
* usually calls this method once the {@link CallbackHandler} has finished
* its work.
- *
+ *
* @return the password. A copy of the internal password is created and
* returned, so subsequent changes to the internal password do not
* affect the result.
diff --git a/libcore/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java b/libcore/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java
index d40ff45..bee7bd3 100644
--- a/libcore/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java
+++ b/libcore/auth/src/main/java/javax/security/auth/callback/UnsupportedCallbackException.java
@@ -20,8 +20,6 @@
/**
* Thrown when a {@link CallbackHandler} does not support a particular {@link
* Callback}.
- *
- * @since Android 1.0
*/
public class UnsupportedCallbackException extends Exception {
@@ -32,7 +30,7 @@
/**
* Creates a new exception instance and initializes it with just the
* unsupported {@code Callback}, but no error message.
- *
+ *
* @param callback
* the {@code Callback}
*/
@@ -44,7 +42,7 @@
/**
* Creates a new exception instance and initializes it with both the
* unsupported {@code Callback} and an error message.
- *
+ *
* @param callback
* the {@code Callback}
* @param message
@@ -57,7 +55,7 @@
/**
* Returns the unsupported {@code Callback} that triggered this exception.
- *
+ *
* @return the {@code Callback}
*/
public Callback getCallback() {
diff --git a/libcore/auth/src/main/java/javax/security/auth/login/LoginException.java b/libcore/auth/src/main/java/javax/security/auth/login/LoginException.java
index a1d6ec0..9433c43 100644
--- a/libcore/auth/src/main/java/javax/security/auth/login/LoginException.java
+++ b/libcore/auth/src/main/java/javax/security/auth/login/LoginException.java
@@ -21,8 +21,6 @@
/**
* Base class for exceptions that are thrown when a login error occurs.
- *
- * @since Android 1.0
*/
public class LoginException extends GeneralSecurityException {
@@ -37,7 +35,7 @@
/**
* Creates a new exception instance and initializes it with a given message.
- *
+ *
* @param message the error message
*/
public LoginException(String message) {
diff --git a/libcore/auth/src/main/java/javax/security/auth/x500/X500Principal.java b/libcore/auth/src/main/java/javax/security/auth/x500/X500Principal.java
index fa9dfe8..41f3a6d 100644
--- a/libcore/auth/src/main/java/javax/security/auth/x500/X500Principal.java
+++ b/libcore/auth/src/main/java/javax/security/auth/x500/X500Principal.java
@@ -29,13 +29,11 @@
/**
* Represents an X.500 principal, which holds the distinguished name of some
- * network entity. An example of a distinguished name is {@code "O=Google,
- * OU=Android, C=US"}. The class can be instantiated from a byte representation
+ * network entity. An example of a distinguished name is {@code "O=SomeOrg,
+ * OU=SomeOrgUnit, C=US"}. The class can be instantiated from a byte representation
* of an object identifier (OID), an ASN.1 DER-encoded version, or a simple
* string holding the distinguished name. The representations must follow either
* RFC 2253, RFC 1779, or RFC2459.
- *
- * @since Android 1.0
*/
public final class X500Principal implements Serializable, Principal {
@@ -65,10 +63,10 @@
/**
* Creates a new X500Principal from a given ASN.1 DER encoding of a
* distinguished name.
- *
+ *
* @param name
* the ASN.1 DER-encoded distinguished name
- *
+ *
* @throws IllegalArgumentException
* if the ASN.1 DER-encoded distinguished name is incorrect
*/
@@ -91,11 +89,11 @@
/**
* Creates a new X500Principal from a given ASN.1 DER encoding of a
* distinguished name.
- *
+ *
* @param in
* an {@code InputStream} holding the ASN.1 DER-encoded
* distinguished name
- *
+ *
* @throws IllegalArgumentException
* if the ASN.1 DER-encoded distinguished name is incorrect
*/
@@ -118,10 +116,10 @@
/**
* Creates a new X500Principal from a string representation of a
* distinguished name.
- *
+ *
* @param name
* the string representation of the distinguished name
- *
+ *
* @throws IllegalArgumentException
* if the string representation of the distinguished name is
* incorrect
@@ -155,8 +153,8 @@
/**
* Returns an ASN.1 DER-encoded representation of the distinguished name
- * contained in this X.500 principal.
- *
+ * contained in this X.500 principal.
+ *
* @return the ASN.1 DER-encoded representation
*/
public byte[] getEncoded() {
@@ -167,9 +165,9 @@
}
/**
- * Returns a human-readable string representation of the distinguished name
+ * Returns a human-readable string representation of the distinguished name
* contained in this X.500 principal.
- *
+ *
* @return the string representation
*/
public String getName() {
@@ -185,12 +183,12 @@
* some canonicalizing operations like removing leading and trailing
* whitespace, lower-casing the whole name, and bringing it into a
* normalized Unicode representation.
- *
+ *
* @param format
* the name of the format to use for the representation
- *
+ *
* @return the string representation
- *
+ *
* @throws IllegalArgumentException
* if the {@code format} argument is not one of the three
* mentioned above
diff --git a/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java b/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
index c80aef8..55e61a9 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/PathClassLoader.java
@@ -56,8 +56,8 @@
/**
* Creates a {@code PathClassLoader} that operates on a given list of files
* and directories. This method is equivalent to calling
- * {@link #PathClassLoader(String, String, ClassLoader) with a {@code null}
- * value for the second argument (see description there).
+ * {@link #PathClassLoader(String, String, ClassLoader)} with a
+ * {@code null} value for the second argument (see description there).
*
* @param path
* the list of files and directories
diff --git a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
index efc25d6..06a67b6 100644
--- a/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
+++ b/libcore/dalvik/src/main/java/dalvik/system/VMDebug.java
@@ -275,6 +275,13 @@
*/
public static native void dumpHprofData(String fileName) throws IOException;
+ /**
+ * Primes the register map cache.
+ *
+ * @hide
+ */
+ public static native boolean cacheRegisterMap(String classAndMethodDesc);
+
/* don't ask */
static native void printThis(Object thisThing, int count, int thing);
diff --git a/libcore/icu/src/main/native/DecimalFormatInterface.cpp b/libcore/icu/src/main/native/DecimalFormatInterface.cpp
index 6221826..7e37d6c 100644
--- a/libcore/icu/src/main/native/DecimalFormatInterface.cpp
+++ b/libcore/icu/src/main/native/DecimalFormatInterface.cpp
@@ -15,6 +15,7 @@
* the VM-specific behavior isolated in VMThread.
*/
+#define LOG_TAG "DecimalFormatInterface"
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
#include "unicode/unum.h"
@@ -28,7 +29,6 @@
#include <string.h>
#include "cutils/log.h"
-#define LOG_TAG "DecimalFormatInterface"
static UBool icuError(JNIEnv *env, UErrorCode errorcode)
{
diff --git a/libcore/icu/src/main/native/ResourceInterface.cpp b/libcore/icu/src/main/native/ResourceInterface.cpp
index 5f9d442..a88e15c 100644
--- a/libcore/icu/src/main/native/ResourceInterface.cpp
+++ b/libcore/icu/src/main/native/ResourceInterface.cpp
@@ -943,7 +943,7 @@
- jclass obj_class = env->FindClass("java/lang/Object");
+ jclass obj_class = env->FindClass("[Ljava/lang/Object;");
jclass integer_class = env->FindClass("java/lang/Integer");
jmethodID integerInit = env->GetMethodID(integer_class, "<init>", "(I)V");
jobjectArray result;
@@ -1207,7 +1207,8 @@
intCurrencySymbol = env->NewStringUTF("XXX");
}
if(currencySymbol == NULL) {
- currencySymbol = env->NewStringUTF("\u00a4");
+ // creating a new string explicitly with the UTF-8 encoding of "\u00a4"
+ currencySymbol = env->NewStringUTF("\xc2\xa4");
}
counter += 2;
diff --git a/libcore/logging/src/main/java/java/util/logging/ConsoleHandler.java b/libcore/logging/src/main/java/java/util/logging/ConsoleHandler.java
index a88cf0c..ef365ca 100644
--- a/libcore/logging/src/main/java/java/util/logging/ConsoleHandler.java
+++ b/libcore/logging/src/main/java/java/util/logging/ConsoleHandler.java
@@ -38,19 +38,13 @@
* handler will use to encode log messages, defaults to {@code null} if this
* property is not found or has an invalid value.
* </ul>
- * </p>
* <p>
* This class is not thread-safe.
- * </p>
- *
- * @since Android 1.0
*/
public class ConsoleHandler extends StreamHandler {
/**
* Constructs a {@code ConsoleHandler} object.
- *
- * @since Android 1.0
*/
public ConsoleHandler() {
super(System.err);
@@ -58,8 +52,6 @@
/**
* Closes this handler. The {@code System.err} is flushed but not closed.
- *
- * @since Android 1.0
*/
@Override
public void close() {
@@ -68,16 +60,13 @@
/**
* Logs a record if necessary. A flush operation will be done.
- *
+ *
* @param record
* the log record to be logged.
- *
- * @since Android 1.0
*/
@Override
public void publish(LogRecord record) {
super.publish(record);
super.flush();
-
}
}
diff --git a/libcore/logging/src/main/java/java/util/logging/ErrorManager.java b/libcore/logging/src/main/java/java/util/logging/ErrorManager.java
index 6f5084c..708ddfa 100644
--- a/libcore/logging/src/main/java/java/util/logging/ErrorManager.java
+++ b/libcore/logging/src/main/java/java/util/logging/ErrorManager.java
@@ -24,51 +24,37 @@
* error that may happen during logging. {@code Handlers} should report errors
* to an {@code ErrorManager}, instead of throwing exceptions, which would
* interfere with the log issuer's execution.
- *
- * @since Android 1.0
*/
public class ErrorManager {
/**
* The error code indicating a failure that does not fit in any of the
* specific types of failures that follow.
- *
- * @since Android 1.0
*/
public static final int GENERIC_FAILURE = 0;
/**
* The error code indicating a failure when writing to an output stream.
- *
- * @since Android 1.0
*/
public static final int WRITE_FAILURE = 1;
/**
* The error code indicating a failure when flushing an output stream.
- *
- * @since Android 1.0
*/
public static final int FLUSH_FAILURE = 2;
/**
* The error code indicating a failure when closing an output stream.
- *
- * @since Android 1.0
*/
public static final int CLOSE_FAILURE = 3;
/**
* The error code indicating a failure when opening an output stream.
- *
- * @since Android 1.0
*/
public static final int OPEN_FAILURE = 4;
/**
* The error code indicating a failure when formatting the error messages.
- *
- * @since Android 1.0
*/
public static final int FORMAT_FAILURE = 5;
@@ -85,20 +71,16 @@
/**
* Constructs an instance of {@code ErrorManager}.
- *
- * @since Android 1.0
*/
public ErrorManager() {
super();
}
/**
- * <p>
* Reports an error using the given message, exception and error code. This
* implementation will write out the message to {@link System#err} on the
* first call and all subsequent calls are ignored. A subclass of this class
* should override this method.
- * </p>
*
* @param message
* the error message, which may be {@code null}.
@@ -108,8 +90,6 @@
* @param errorCode
* the error code that identifies the type of error; see the
* constant fields of this class for possible values.
- *
- * @since Android 1.0
*/
public void error(String message, Exception exception, int errorCode) {
synchronized (this) {
@@ -119,7 +99,7 @@
called = true;
}
System.err.println(this.getClass().getName()
- + ": " + FAILURES[errorCode]); //$NON-NLS-1$
+ + ": " + FAILURES[errorCode]); //$NON-NLS-1$
if (message != null) {
// logging.1E=Error message - {0}
System.err.println(Messages.getString("logging.1E", message)); //$NON-NLS-1$
diff --git a/libcore/logging/src/main/java/java/util/logging/FileHandler.java b/libcore/logging/src/main/java/java/util/logging/FileHandler.java
index af71a6d..e1eba9e 100644
--- a/libcore/logging/src/main/java/java/util/logging/FileHandler.java
+++ b/libcore/logging/src/main/java/java/util/logging/FileHandler.java
@@ -38,48 +38,45 @@
* When a set of files is used and a given amount of data has been written to
* one file, then this file is closed and another file is opened. The name of
* these files are generated by given name pattern, see below for details.
- * </p>
+ * When the files have all been filled the Handler returns to the first and goes
+ * through the set again.
* <p>
* By default, the I/O buffering mechanism is enabled, but when each log record
* is complete, it is flushed out.
- * </p>
* <p>
* {@code XMLFormatter} is the default formatter for {@code FileHandler}.
- * </p>
* <p>
* {@code FileHandler} reads the following {@code LogManager} properties for
* initialization; if a property is not defined or has an invalid value, a
* default value is used.
* <ul>
- * <li>java.util.logging.FileHandler.level specifies the level for this
- * {@code Handler}, defaults to {@code Level.ALL}.</li>
+ * <li>java.util.logging.FileHandler.append specifies whether this
+ * {@code FileHandler} should append onto existing files, defaults to
+ * {@code false}.</li>
+ * <li>java.util.logging.FileHandler.count specifies how many output files to
+ * rotate, defaults to 1.</li>
* <li>java.util.logging.FileHandler.filter specifies the {@code Filter} class
* name, defaults to no {@code Filter}.</li>
* <li>java.util.logging.FileHandler.formatter specifies the {@code Formatter}
* class, defaults to {@code java.util.logging.XMLFormatter}.</li>
* <li>java.util.logging.FileHandler.encoding specifies the character set
* encoding name, defaults to the default platform encoding.</li>
+ * <li>java.util.logging.FileHandler.level specifies the level for this
+ * {@code Handler}, defaults to {@code Level.ALL}.</li>
* <li>java.util.logging.FileHandler.limit specifies the maximum number of
* bytes to write to any one file, defaults to zero, which means no limit.</li>
- * <li>java.util.logging.FileHandler.count specifies how many output files to
- * rotate, defaults to 1.</li>
* <li>java.util.logging.FileHandler.pattern specifies name pattern for the
* output files. See below for details. Defaults to "%h/java%u.log".</li>
- * <li>java.util.logging.FileHandler.append specifies whether this
- * {@code FileHandler} should append onto existing files, defaults to
- * {@code false}.</li>
* </ul>
- * </p>
* <p>
* Name pattern is a string that may include some special substrings, which will
* be replaced to generate output files:
- * </p>
* <ul>
* <li>"/" represents the local pathname separator</li>
- * <li>"%t" represents the system's temporary directory</li>
+ * <li>"%g" represents the generation number to distinguish rotated logs</li>
* <li>"%h" represents the home directory of the current user, which is
* specified by "user.home" system property</li>
- * <li>"%g" represents the generation number to distinguish rotated logs</li>
+ * <li>"%t" represents the system's temporary directory</li>
* <li>"%u" represents a unique number to resolve conflicts</li>
* <li>"%%" represents the percent sign character '%'</li>
* </ul>
@@ -88,7 +85,6 @@
* follow the sequence 0, 1, 2.... If the file count is larger than one, but the
* generation field("%g") has not been specified in the pattern, then the
* generation number after a dot will be added to the end of the file name.
- * </p>
* <p>
* The "%u" unique field is used to avoid conflicts and is set to 0 at first. If
* one {@code FileHandler} tries to open the filename which is currently in use
@@ -98,8 +94,6 @@
* value will be added to the end of the filename in question immediately to the
* right of a dot. The generation of unique IDs for avoiding conflicts is only
* guaranteed to work reliably when using a local disk file system.
- * </p>
- * @since Android 1.0
*/
public class FileHandler extends StreamHandler {
@@ -150,7 +144,7 @@
/**
* Construct a {@code FileHandler} using {@code LogManager} properties or
* their default value.
- *
+ *
* @throws IOException
* if any I/O error occurs.
* @throws SecurityException
@@ -159,7 +153,6 @@
* handler; required permissions include
* {@code LogPermission("control")},
* {@code FilePermission("write")} etc.
- * @since Android 1.0
*/
public FileHandler() throws IOException {
init(null, null, null, null);
@@ -232,21 +225,22 @@
setOutputStream(output);
}
+ @SuppressWarnings("nls")
private void initProperties(String p, Boolean a, Integer l, Integer c) {
- super.initProperties("ALL", null, "java.util.logging.XMLFormatter", //$NON-NLS-1$//$NON-NLS-2$
+ super.initProperties("ALL", null, "java.util.logging.XMLFormatter",
null);
String className = this.getClass().getName();
- pattern = (null == p) ? getStringProperty(className + ".pattern", //$NON-NLS-1$
+ pattern = (null == p) ? getStringProperty(className + ".pattern",
DEFAULT_PATTERN) : p;
- if (null == pattern || "".equals(pattern)) { //$NON-NLS-1$
+ if (null == pattern || "".equals(pattern)) {
// logging.19=Pattern cannot be empty
- throw new NullPointerException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new NullPointerException(Messages.getString("logging.19"));
}
- append = (null == a) ? getBooleanProperty(className + ".append", //$NON-NLS-1$
+ append = (null == a) ? getBooleanProperty(className + ".append",
DEFAULT_APPEND) : a.booleanValue();
- count = (null == c) ? getIntProperty(className + ".count", //$NON-NLS-1$
+ count = (null == c) ? getIntProperty(className + ".count",
DEFAULT_COUNT) : c.intValue();
- limit = (null == l) ? getIntProperty(className + ".limit", //$NON-NLS-1$
+ limit = (null == l) ? getIntProperty(className + ".limit",
DEFAULT_LIMIT) : l.intValue();
count = count < 1 ? DEFAULT_COUNT : count;
limit = limit < 0 ? DEFAULT_LIMIT : limit;
@@ -279,7 +273,7 @@
/**
* Transform the pattern to the valid file name, replacing any patterns, and
* applying generation and uniqueID if present.
- *
+ *
* @param gen
* generation of this file
* @return transformed filename ready for use.
@@ -396,9 +390,9 @@
* Constructs a new {@code FileHandler}. The given name pattern is used as
* output filename, the file limit is set to zero (no limit), the file count
* is set to one; the remaining configuration is done using
- * {@code LogManager} properties or their default values. This handler write
- * to only one file without size limit.
- *
+ * {@code LogManager} properties or their default values. This handler
+ * writes to only one file with no size limit.
+ *
* @param pattern
* the name pattern for the output file.
* @throws IOException
@@ -413,7 +407,6 @@
* if the pattern is empty.
* @throws NullPointerException
* if the pattern is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern) throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
@@ -429,9 +422,9 @@
* output filename, the file limit is set to zero (no limit), the file count
* is initialized to one and the value of {@code append} becomes the new
* instance's append mode. The remaining configuration is done using
- * {@code LogManager} properties. This handler write to only one file
- * without size limit.
- *
+ * {@code LogManager} properties. This handler writes to only one file
+ * with no size limit.
+ *
* @param pattern
* the name pattern for the output file.
* @param append
@@ -448,11 +441,10 @@
* if {@code pattern} is empty.
* @throws NullPointerException
* if {@code pattern} is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern, boolean append) throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
}
init(pattern, Boolean.valueOf(append), Integer.valueOf(DEFAULT_LIMIT),
@@ -466,7 +458,7 @@
* is done using {@code LogManager} properties. This handler is configured
* to write to a rotating set of count files, when the limit of bytes has
* been written to one output file, another file will be opened instead.
- *
+ *
* @param pattern
* the name pattern for the output file.
* @param limit
@@ -487,11 +479,10 @@
* {@code count < 1}.
* @throws NullPointerException
* if {@code pattern} is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern, int limit, int count) throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
}
if (limit < 0 || count < 1) {
// logging.1B=The limit and count property must be larger than 0 and
@@ -509,7 +500,7 @@
* {@code LogManager} properties. This handler is configured to write to a
* rotating set of count files, when the limit of bytes has been written to
* one output file, another file will be opened instead.
- *
+ *
* @param pattern
* the name pattern for the output file.
* @param limit
@@ -532,12 +523,11 @@
* {@code count < 1}.
* @throws NullPointerException
* if {@code pattern} is {@code null}.
- * @since Android 1.0
*/
public FileHandler(String pattern, int limit, int count, boolean append)
throws IOException {
if (pattern.equals("")) { //$NON-NLS-1$
- throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString("logging.19")); //$NON-NLS-1$
}
if (limit < 0 || count < 1) {
// logging.1B=The limit and count property must be larger than 0 and
@@ -550,14 +540,13 @@
/**
* Flushes and closes all opened files.
- *
+ *
* @throws SecurityException
* if a security manager exists and it determines that the
* caller does not have the required permissions to control this
* handler; required permissions include
* {@code LogPermission("control")},
* {@code FilePermission("write")} etc.
- * @since Android 1.0
*/
@Override
public void close() {
@@ -577,10 +566,9 @@
/**
* Publish a {@code LogRecord}.
- *
+ *
* @param record
* the log record to publish.
- * @since Android 1.0
*/
@Override
public void publish(LogRecord record) {
diff --git a/libcore/logging/src/main/java/java/util/logging/Filter.java b/libcore/logging/src/main/java/java/util/logging/Filter.java
index e81f216..f5dbd9f 100644
--- a/libcore/logging/src/main/java/java/util/logging/Filter.java
+++ b/libcore/logging/src/main/java/java/util/logging/Filter.java
@@ -20,8 +20,6 @@
/**
* A {@code Filter} provides a mechanism for exercising fine-grained control
* over which records get logged.
- *
- * @since Android 1.0
*/
public interface Filter {
@@ -32,7 +30,6 @@
* the {@link LogRecord} to be checked.
* @return {@code true} if the supplied log record needs to be logged,
* {@code false} otherwise.
- * @since Android 1.0
*/
boolean isLoggable(LogRecord record);
}
diff --git a/libcore/logging/src/main/java/java/util/logging/Formatter.java b/libcore/logging/src/main/java/java/util/logging/Formatter.java
index 2941c24..f9b0d25 100644
--- a/libcore/logging/src/main/java/java/util/logging/Formatter.java
+++ b/libcore/logging/src/main/java/java/util/logging/Formatter.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.text.MessageFormat;
@@ -26,41 +25,24 @@
* string representation. Head and tail strings are sometimes used to wrap a set
* of records. The {@code getHead} and {@code getTail} methods are used for this
* purpose.
- *
- * @since Android 1.0
*/
public abstract class Formatter {
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
/**
* Constructs a {@code Formatter} object.
- *
- * @since Android 1.0
*/
protected Formatter() {
super();
}
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
/**
* Converts a {@link LogRecord} object into a string representation. The
* resulted string is usually localized and includes the message field of
* the record.
- *
+ *
* @param r
* the log record to be formatted into a string.
* @return the formatted string.
- * @since Android 1.0
*/
public abstract String format(LogRecord r);
@@ -71,16 +53,13 @@
* <p>
* The message string is firstly localized using the {@code ResourceBundle}
* object associated with the supplied {@code LogRecord}.
- * </p>
* <p>
* Notice : if message contains "{0", then java.text.MessageFormat is used.
* Otherwise no formatting is performed.
- * </p>
- *
+ *
* @param r
* the log record to be formatted.
* @return the string resulted from the formatting.
- * @since Android 1.0
*/
public String formatMessage(LogRecord r) {
String pattern = r.getMessage();
@@ -114,14 +93,12 @@
/**
* Gets the head string used to wrap a set of log records. This base class
* always returns an empty string.
- *
+ *
* @param h
* the target handler.
* @return the head string used to wrap a set of log records, empty in this
* implementation.
- * @since Android 1.0
*/
- @SuppressWarnings("unused")
public String getHead(Handler h) {
return ""; //$NON-NLS-1$
}
@@ -129,17 +106,13 @@
/**
* Gets the tail string used to wrap a set of log records. This base class
* always returns the empty string.
- *
+ *
* @param h
* the target handler.
* @return the tail string used to wrap a set of log records, empty in this
* implementation.
- * @since Android 1.0
*/
- @SuppressWarnings("unused")
public String getTail(Handler h) {
return ""; //$NON-NLS-1$
}
-
}
-
diff --git a/libcore/logging/src/main/java/java/util/logging/Handler.java b/libcore/logging/src/main/java/java/util/logging/Handler.java
index d28bce0..a5b92a0 100644
--- a/libcore/logging/src/main/java/java/util/logging/Handler.java
+++ b/libcore/logging/src/main/java/java/util/logging/Handler.java
@@ -15,13 +15,12 @@
* limitations under the License.
*/
-
package java.util.logging;
+import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
-import java.io.UnsupportedEncodingException;
import org.apache.harmony.logging.internal.nls.Messages;
@@ -29,24 +28,11 @@
* A {@code Handler} object accepts a logging request and exports the desired
* messages to a target, for example, a file, the console, etc. It can be
* disabled by setting its logging level to {@code Level.OFF}.
- *
- * @since Android 1.0
*/
public abstract class Handler {
- /*
- * -------------------------------------------------------------------
- * Constants
- * -------------------------------------------------------------------
- */
private static final Level DEFAULT_LEVEL = Level.ALL;
- /*
- * -------------------------------------------------------------------
- * Instance variables
- * -------------------------------------------------------------------
- */
-
// the error manager to report errors during logging
private ErrorManager errorMan;
@@ -65,18 +51,10 @@
// class name, used for property reading
private String prefix;
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
/**
* Constructs a {@code Handler} object with a default error manager instance
* {@code ErrorManager}, the default encoding, and the default logging
* level {@code Level.ALL}. It has no filter and no formatter.
- *
- * @since Android 1.0
*/
protected Handler() {
this.errorMan = new ErrorManager();
@@ -87,12 +65,6 @@
this.prefix = this.getClass().getName();
}
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
// get a instance from given class name, using Class.forName()
private Object getDefaultInstance(String className) {
Object result = null;
@@ -102,7 +74,7 @@
try {
result = Class.forName(className).newInstance();
} catch (Exception e) {
- //ignore
+ // ignore
}
return result;
}
@@ -110,7 +82,8 @@
// get a instance from given class name, using context classloader
private Object getCustomizeInstance(final String className)
throws Exception {
- Class<?> c = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+ Class<?> c = AccessController
+ .doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
public Class<?> run() throws Exception {
ClassLoader loader = Thread.currentThread()
.getContextClassLoader();
@@ -126,22 +99,22 @@
// print error message in some format
void printInvalidPropMessage(String key, String value, Exception e) {
// logging.12=Invalid property value for
- String msg = new StringBuilder().append(Messages.getString("logging.12")) //$NON-NLS-1$
+ String msg = new StringBuilder().append(
+ Messages.getString("logging.12")) //$NON-NLS-1$
.append(prefix).append(":").append(key).append("/").append( //$NON-NLS-1$//$NON-NLS-2$
value).toString();
errorMan.error(msg, e, ErrorManager.GENERIC_FAILURE);
}
- /*
+ /**
* init the common properties, including filter, level, formatter, and
* encoding
*/
- @SuppressWarnings("unused")
void initProperties(String defaultLevel, String defaultFilter,
String defaultFormatter, String defaultEncoding) {
LogManager manager = LogManager.getLogManager();
- //set filter
+ // set filter
final String filterName = manager.getProperty(prefix + ".filter"); //$NON-NLS-1$
if (null != filterName) {
try {
@@ -154,7 +127,7 @@
filter = (Filter) getDefaultInstance(defaultFilter);
}
- //set level
+ // set level
String levelName = manager.getProperty(prefix + ".level"); //$NON-NLS-1$
if (null != levelName) {
try {
@@ -167,7 +140,7 @@
level = Level.parse(defaultLevel);
}
- //set formatter
+ // set formatter
final String formatterName = manager.getProperty(prefix + ".formatter"); //$NON-NLS-1$
if (null != formatterName) {
try {
@@ -180,7 +153,7 @@
formatter = (Formatter) getDefaultInstance(defaultFormatter);
}
- //set encoding
+ // set encoding
final String encodingName = manager.getProperty(prefix + ".encoding"); //$NON-NLS-1$
try {
internalSetEncoding(encodingName);
@@ -193,37 +166,31 @@
* Closes this handler. A flush operation will be performed and all the
* associated resources will be freed. Client applications should not use
* this handler after closing it.
- *
+ *
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- *
- * @since Android 1.0
*/
public abstract void close();
/**
* Flushes any buffered output.
- *
- * @since Android 1.0
*/
public abstract void flush();
/**
* Accepts a logging request and sends it to the the target.
- *
+ *
* @param record
* the log record to be logged; {@code null} records are ignored.
- * @since Android 1.0
*/
public abstract void publish(LogRecord record);
/**
* Gets the character encoding used by this handler, {@code null} for
* default encoding.
- *
+ *
* @return the character encoding used by this handler.
- * @since Android 1.0
*/
public String getEncoding() {
return this.encoding;
@@ -232,12 +199,11 @@
/**
* Gets the error manager used by this handler to report errors during
* logging.
- *
+ *
* @return the error manager used by this handler.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public ErrorManager getErrorManager() {
LogManager.getLogManager().checkAccess();
@@ -246,9 +212,8 @@
/**
* Gets the filter used by this handler.
- *
+ *
* @return the filter used by this handler (possibly {@code null}).
- * @since Android 1.0
*/
public Filter getFilter() {
return this.filter;
@@ -256,9 +221,8 @@
/**
* Gets the formatter used by this handler to format the logging messages.
- *
+ *
* @return the formatter used by this handler (possibly {@code null}).
- * @since Android 1.0
*/
public Formatter getFormatter() {
return this.formatter;
@@ -267,9 +231,8 @@
/**
* Gets the logging level of this handler, records with levels lower than
* this value will be dropped.
- *
+ *
* @return the logging level of this handler.
- * @since Android 1.0
*/
public Level getLevel() {
return this.level;
@@ -278,12 +241,11 @@
/**
* Determines whether the supplied log record needs to be logged. The
* logging levels will be checked as well as the filter.
- *
+ *
* @param record
* the log record to be checked.
* @return {@code true} if the supplied log record needs to be logged,
* otherwise {@code false}.
- * @since Android 1.0
*/
public boolean isLoggable(LogRecord record) {
if (null == record) {
@@ -302,14 +264,13 @@
* {@code ErrorManager} is used for that purpose. No security checks are
* done, therefore this is compatible with environments where the caller
* is non-privileged.
- *
+ *
* @param msg
* the error message, may be {@code null}.
* @param ex
* the associated exception, may be {@code null}.
* @param code
* an {@code ErrorManager} error code.
- * @since Android 1.0
*/
protected void reportError(String msg, Exception ex, int code) {
this.errorMan.error(msg, ex, code);
@@ -319,12 +280,11 @@
* Sets the character encoding used by this handler. A {@code null} value
* indicates the use of the default encoding. This internal method does
* not check security.
- *
+ *
* @param newEncoding
* the character encoding to set.
* @throws UnsupportedEncodingException
* if the specified encoding is not supported by the runtime.
- * @since Android 1.0
*/
void internalSetEncoding(String newEncoding)
throws UnsupportedEncodingException {
@@ -347,7 +307,7 @@
/**
* Sets the character encoding used by this handler, {@code null} indicates
* a default encoding.
- *
+ *
* @param encoding
* the character encoding to set.
* @throws SecurityException
@@ -355,7 +315,6 @@
* have the required permission.
* @throws UnsupportedEncodingException
* if the specified encoding is not supported by the runtime.
- * @since Android 1.0
*/
public void setEncoding(String encoding) throws SecurityException,
UnsupportedEncodingException {
@@ -365,7 +324,7 @@
/**
* Sets the error manager for this handler.
- *
+ *
* @param em
* the error manager to set.
* @throws NullPointerException
@@ -373,7 +332,6 @@
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setErrorManager(ErrorManager em) {
LogManager.getLogManager().checkAccess();
@@ -385,13 +343,12 @@
/**
* Sets the filter to be used by this handler.
- *
+ *
* @param newFilter
* the filter to set, may be {@code null}.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setFilter(Filter newFilter) {
LogManager.getLogManager().checkAccess();
@@ -401,7 +358,7 @@
/**
* Sets the formatter to be used by this handler. This internal method does
* not check security.
- *
+ *
* @param newFormatter
* the formatter to set.
*/
@@ -414,7 +371,7 @@
/**
* Sets the formatter to be used by this handler.
- *
+ *
* @param newFormatter
* the formatter to set.
* @throws NullPointerException
@@ -422,7 +379,6 @@
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setFormatter(Formatter newFormatter) {
LogManager.getLogManager().checkAccess();
@@ -432,7 +388,7 @@
/**
* Sets the logging level of the messages logged by this handler, levels
* lower than this value will be dropped.
- *
+ *
* @param newLevel
* the logging level to set.
* @throws NullPointerException
@@ -440,7 +396,6 @@
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setLevel(Level newLevel) {
if (null == newLevel) {
@@ -450,4 +405,3 @@
this.level = newLevel;
}
}
-
diff --git a/libcore/logging/src/main/java/java/util/logging/Level.java b/libcore/logging/src/main/java/java/util/logging/Level.java
index 32ba017..f988127 100644
--- a/libcore/logging/src/main/java/java/util/logging/Level.java
+++ b/libcore/logging/src/main/java/java/util/logging/Level.java
@@ -41,8 +41,6 @@
* INFO, WARNING, SEVERE. There are two additional predefined levels, which are
* ALL and OFF. ALL indicates logging all messages, and OFF indicates logging no
* messages.
- * </p>
- * @since Android 1.0
*/
public class Level implements Serializable {
@@ -52,70 +50,52 @@
/**
* The OFF level provides no logging messages.
- *
- * @since Android 1.0
*/
public static final Level OFF = new Level("OFF", Integer.MAX_VALUE); //$NON-NLS-1$
/**
* The SEVERE level provides severe failure messages.
- *
- * @since Android 1.0
*/
public static final Level SEVERE = new Level("SEVERE", 1000); //$NON-NLS-1$
/**
* The WARNING level provides warnings.
- *
- * @since Android 1.0
*/
public static final Level WARNING = new Level("WARNING", 900); //$NON-NLS-1$
/**
* The INFO level provides informative messages.
- *
- * @since Android 1.0
*/
public static final Level INFO = new Level("INFO", 800); //$NON-NLS-1$
/**
* The CONFIG level provides static configuration messages.
- *
- * @since Android 1.0
*/
public static final Level CONFIG = new Level("CONFIG", 700); //$NON-NLS-1$
/**
* The FINE level provides tracing messages.
- *
- * @since Android 1.0
*/
public static final Level FINE = new Level("FINE", 500); //$NON-NLS-1$
/**
* The FINER level provides more detailed tracing messages.
- *
- * @since Android 1.0
*/
public static final Level FINER = new Level("FINER", 400); //$NON-NLS-1$
/**
* The FINEST level provides highly detailed tracing messages.
- *
- * @since Android 1.0
*/
public static final Level FINEST = new Level("FINEST", 300); //$NON-NLS-1$
/**
* The ALL level provides all logging messages.
- *
- * @since Android 1.0
*/
public static final Level ALL = new Level("ALL", Integer.MIN_VALUE); //$NON-NLS-1$
/**
* Parses a level name into a {@code Level} object.
- *
+ *
* @param name
* the name of the desired {@code level}, which cannot be
* {@code null}.
@@ -124,13 +104,8 @@
* if {@code name} is {@code null}.
* @throws IllegalArgumentException
* if {@code name} is not valid.
- * @since Android 1.0
*/
public static Level parse(String name) throws IllegalArgumentException {
- // BEGIN android-note
- // final modifier removed and IAE added to get closer to the RI
- // copied from newer version of harmony
- // END android-note
if (name == null) {
// logging.1C=The 'name' parameter is null.
throw new NullPointerException(Messages.getString("logging.1C")); //$NON-NLS-1$
@@ -155,8 +130,8 @@
if (isNameAnInt) {
/*
- * Loop through levels a second time, so that the
- * returned instance will be passed on the order of construction.
+ * Loop through levels a second time, so that the returned
+ * instance will be passed on the order of construction.
*/
for (Level level : levels) {
if (nameAsInt == level.intValue()) {
@@ -168,7 +143,8 @@
if (!isNameAnInt) {
// logging.1D=Cannot parse this name: {0}
- throw new IllegalArgumentException(Messages.getString("logging.1D", name)); //$NON-NLS-1$
+ throw new IllegalArgumentException(Messages.getString(
+ "logging.1D", name)); //$NON-NLS-1$
}
return new Level(name, nameAsInt);
@@ -176,21 +152,21 @@
/**
* The name of this Level.
- *
+ *
* @serial
*/
private final String name;
/**
* The integer value indicating the level.
- *
+ *
* @serial
*/
private final int value;
/**
* The name of the resource bundle used to localize the level name.
- *
+ *
* @serial
*/
private final String resourceBundleName;
@@ -204,14 +180,13 @@
/**
* Constructs an instance of {@code Level} taking the supplied name and
* level value.
- *
+ *
* @param name
* the name of the level.
* @param level
* an integer value indicating the level.
* @throws NullPointerException
* if {@code name} is {@code null}.
- * @since Android 1.0
*/
protected Level(String name, int level) {
this(name, level, null);
@@ -220,7 +195,7 @@
/**
* Constructs an instance of {@code Level} taking the supplied name, level
* value and resource bundle name.
- *
+ *
* @param name
* the name of the level.
* @param level
@@ -229,7 +204,6 @@
* the name of the resource bundle to use.
* @throws NullPointerException
* if {@code name} is {@code null}.
- * @since Android 1.0
*/
protected Level(String name, int level, String resourceBundleName) {
if (name == null) {
@@ -256,9 +230,8 @@
/**
* Gets the name of this level.
- *
+ *
* @return this level's name.
- * @since Android 1.0
*/
public String getName() {
return this.name;
@@ -266,9 +239,8 @@
/**
* Gets the name of the resource bundle associated with this level.
- *
+ *
* @return the name of this level's resource bundle.
- * @since Android 1.0
*/
public String getResourceBundleName() {
return this.resourceBundleName;
@@ -276,20 +248,17 @@
/**
* Gets the integer value indicating this level.
- *
+ *
* @return this level's integer value.
- * @since Android 1.0
*/
public final int intValue() {
return this.value;
}
/**
- * <p>
* Serialization helper method to maintain singletons and add any new
* levels.
- * </p>
- *
+ *
* @return the resolved instance.
*/
private Object readResolve() {
@@ -298,7 +267,7 @@
if (value != level.value) {
continue;
}
- if (!name.equals(name)) {
+ if (!name.equals(level.name)) {
continue;
}
if (resourceBundleName == level.resourceBundleName) {
@@ -316,7 +285,7 @@
/**
* Serialization helper to setup transient resource bundle instance.
- *
+ *
* @param in
* the input stream to read the instance data from.
* @throws IOException
@@ -324,7 +293,8 @@
* @throws ClassNotFoundException
* if a class is not found.
*/
- private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ private void readObject(ObjectInputStream in) throws IOException,
+ ClassNotFoundException {
in.defaultReadObject();
if (resourceBundleName != null) {
try {
@@ -339,9 +309,8 @@
* Gets the localized name of this level. The default locale is used. If no
* resource bundle is associated with this level then the original level
* name is returned.
- *
+ *
* @return the localized name of this level.
- * @since Android 1.0
*/
public String getLocalizedName() {
if (rb == null) {
@@ -358,12 +327,11 @@
/**
* Compares two {@code Level} objects for equality. They are considered to
* be equal if they have the same level value.
- *
+ *
* @param o
* the other object to compare this level to.
* @return {@code true} if this object equals to the supplied object,
* {@code false} otherwise.
- * @since Android 1.0
*/
@Override
public boolean equals(Object o) {
@@ -380,9 +348,8 @@
/**
* Returns the hash code of this {@code Level} object.
- *
+ *
* @return this level's hash code.
- * @since Android 1.0
*/
@Override
public int hashCode() {
@@ -392,9 +359,8 @@
/**
* Returns the string representation of this {@code Level} object. In
* this case, it is the level's name.
- *
+ *
* @return the string representation of this level.
- * @since Android 1.0
*/
@Override
public final String toString() {
diff --git a/libcore/logging/src/main/java/java/util/logging/LogManager.java b/libcore/logging/src/main/java/java/util/logging/LogManager.java
index 8409b81..308daaf 100644
--- a/libcore/logging/src/main/java/java/util/logging/LogManager.java
+++ b/libcore/logging/src/main/java/java/util/logging/LogManager.java
@@ -24,6 +24,10 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+// BEGIN android-removed
+//import java.lang.management.ManagementFactory;
+//import java.lang.reflect.Method;
+// END android-removed
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
@@ -33,13 +37,11 @@
import java.util.Properties;
import java.util.Set;
import java.util.StringTokenizer;
+
// BEGIN android-removed
-// import java.lang.management.ManagementFactory;
-// import java.lang.reflect.Method;
-// import javax.management.MBeanServer;
-// import javax.management.ObjectName;
-// import javax.management.ObjectInstance;
-// import javax.management.MalformedObjectNameException;
+//import javax.management.MBeanServer;
+//import javax.management.ObjectInstance;
+//import javax.management.ObjectName;
// END android-removed
import org.apache.harmony.logging.internal.nls.Messages;
@@ -49,23 +51,19 @@
* logging framework, and to manage a hierarchical namespace of all named
* {@code Logger} objects.
* <p>
- *
* There is only one global {@code LogManager} instance in the
* application, which can be get by calling static method
* {@link #getLogManager()}. This instance is created and
* initialized during class initialization and cannot be changed.
- * </p>
* <p>
* The {@code LogManager} class can be specified by
* java.util.logging.manager system property, if the property is unavailable or
* invalid, the default class {@link java.util.logging.LogManager} will
* be used.
- * </p>
* <p>
- * When initialization, {@code LogManager} read its configuration from a
+ * On initialization, {@code LogManager} reads its configuration from a
* properties file, which by default is the "lib/logging.properties" in the JRE
* directory.
- * </p>
* <p>
* However, two optional system properties can be used to customize the initial
* configuration process of {@code LogManager}.
@@ -73,31 +71,26 @@
* <li>"java.util.logging.config.class"</li>
* <li>"java.util.logging.config.file"</li>
* </ul>
- * </p>
* <p>
* These two properties can be set in three ways, by the Preferences API, by the
* "java" command line property definitions, or by system property definitions
* passed to JNI_CreateJavaVM.
- * </p>
* <p>
* The "java.util.logging.config.class" should specifies a class name. If it is
* set, this given class will be loaded and instantiated during
* {@code LogManager} initialization, so that this object's default
* constructor can read the initial configuration and define properties for
* {@code LogManager}.
- * </p>
* <p>
* If "java.util.logging.config.class" property is not set, or it is invalid, or
* some exception is thrown during the instantiation, then the
* "java.util.logging.config.file" system property can be used to specify a
* properties file. The {@code LogManager} will read initial
* configuration from this file.
- * </p>
* <p>
* If neither of these properties is defined, or some exception is thrown
* during these two properties using, the {@code LogManager} will read
* its initial configuration from default properties file, as described above.
- * </p>
* <p>
* The global logging properties may include:
* <ul>
@@ -113,22 +106,18 @@
* some logger, etc. These classes will be loaded and instantiated during
* {@code LogManager} configuration</li>
* </ul>
- * </p>
* <p>
* This class, together with any handler and configuration classes associated
* with it, <b>must</b> be loaded from the system classpath when
* {@code LogManager} configuration occurs.
- * </p>
* <p>
* Besides global properties, the properties for loggers and Handlers can be
* specified in the property files. The names of these properties will start
* with the complete dot separated names for the handlers or loggers.
- * </p>
* <p>
* In the {@code LogManager}'s hierarchical namespace,
* {@code Loggers} are organized based on their dot separated names. For
* example, "x.y.z" is child of "x.y".
- * </p>
* <p>
* Levels for {@code Loggers} can be defined by properties whose name end
* with ".level". Thus "alogger.level" defines a level for the logger named as
@@ -136,23 +125,15 @@
* properties are read and applied in the same order as they are specified in
* the property file. The root logger's level can be defined by the property
* named as ".level".
- * </p>
* <p>
* All methods on this type can be taken as being thread safe.
- * </p>
- *
+ *
*/
public class LogManager {
- /*
- * -------------------------------------------------------------------
- * Class variables
- * -------------------------------------------------------------------
- */
// The line separator of the underlying OS
// Use privileged code to read the line.separator system property
- private static final String lineSeparator =
- getPrivilegedSystemProperty("line.separator"); //$NON-NLS-1$
+ private static final String lineSeparator = getPrivilegedSystemProperty("line.separator"); //$NON-NLS-1$
// The shared logging permission
private static final LoggingPermission perm = new LoggingPermission(
@@ -160,63 +141,55 @@
// the singleton instance
static LogManager manager;
-
+
/**
* The {@code String} value of the {@link LoggingMXBean}'s ObjectName.
- *
- * @since Android 1.0
*/
- public static final String LOGGING_MXBEAN_NAME =
- "java.util.logging:type=Logging"; //$NON-NLS-1$
+ public static final String LOGGING_MXBEAN_NAME = "java.util.logging:type=Logging"; //$NON-NLS-1$
/**
* Get the {@code LoggingMXBean} instance. this implementation always throws
* an UnsupportedOperationException.
- *
+ *
* @return the {@code LoggingMXBean} instance
*/
public static LoggingMXBean getLoggingMXBean() {
- // BEGIN android-added
- throw new UnsupportedOperationException();
- // END android-added
- // BEGIN android-removed
- // try {
- // ObjectName loggingMXBeanName = new ObjectName(LOGGING_MXBEAN_NAME);
- // MBeanServer platformBeanServer =
- // ManagementFactory.getPlatformMBeanServer();
- // Set loggingMXBeanSet = platformBeanServer.queryMBeans(
- // loggingMXBeanName, null);
- //
- // if (loggingMXBeanSet.size() != 1) {
- // // logging.21=There Can Be Only One logging MX bean.
- // throw new AssertionError(Messages.getString("logging.21"));
- // }
- //
- // Iterator i = loggingMXBeanSet.iterator();
- // ObjectInstance loggingMXBeanOI = (ObjectInstance) i.next();
- // String lmxbcn = loggingMXBeanOI.getClassName();
- // Class lmxbc = Class.forName(lmxbcn);
- // Method giMethod = lmxbc.getDeclaredMethod("getInstance");
- // giMethod.setAccessible(true);
- // LoggingMXBean lmxb = (LoggingMXBean)
- // giMethod.invoke(null, new Object[] {});
- //
- // return lmxb;
- // } catch (Exception e) {
- // //TODO
- // //e.printStackTrace();
- // }
- // // logging.22=Exception occurred while getting the logging MX bean.
- // throw new AssertionError(Messages.getString("logging.22")); //$NON-NLS-1$
- // END android-removed
- }
+ // BEGIN android-added
+ throw new UnsupportedOperationException();
+ // END android-added
+ // BEGIN android-removed
+ // try {
+ // ObjectName loggingMXBeanName = new ObjectName(LOGGING_MXBEAN_NAME);
+ // MBeanServer platformBeanServer = ManagementFactory
+ // .getPlatformMBeanServer();
+ // Set<?> loggingMXBeanSet = platformBeanServer.queryMBeans(
+ // loggingMXBeanName, null);
+ //
+ // if (loggingMXBeanSet.size() != 1) {
+ // // logging.21=There Can Be Only One logging MX bean.
+ // throw new AssertionError(Messages.getString("logging.21")); //$NON-NLS-1$
+ // }
+ //
+ // Iterator<?> i = loggingMXBeanSet.iterator();
+ // ObjectInstance loggingMXBeanOI = (ObjectInstance) i.next();
+ // String lmxbcn = loggingMXBeanOI.getClassName();
+ // Class<?> lmxbc = Class.forName(lmxbcn);
+ // Method giMethod = lmxbc.getDeclaredMethod("getInstance"); //$NON-NLS-1$
+ // giMethod.setAccessible(true);
+ // LoggingMXBean lmxb = (LoggingMXBean) giMethod.invoke(null,
+ // new Object[] {});
+ //
+ // return lmxb;
+ // } catch (Exception e) {
+ // // TODO
+ // // e.printStackTrace();
+ // }
+ // // logging.22=Exception occurred while getting the logging MX bean.
+ // throw new AssertionError(Messages.getString("logging.22")); //$NON-NLS-1$
+ // END android-removed
+ }
- /*
- * -------------------------------------------------------------------
- * Instance variables
- * -------------------------------------------------------------------
- */
- //FIXME: use weak reference to avoid heap memory leak
+ // FIXME: use weak reference to avoid heap memory leak
private Hashtable<String, Logger> loggers;
// the configuration properties
@@ -225,19 +198,13 @@
// the property change listener
private PropertyChangeSupport listeners;
- /*
- * -------------------------------------------------------------------
- * Global initialization
- * -------------------------------------------------------------------
- */
-
static {
// init LogManager singleton instance
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
- String className = System.getProperty(
- "java.util.logging.manager"); //$NON-NLS-1$
-
+ String className = System
+ .getProperty("java.util.logging.manager"); //$NON-NLS-1$
+
if (null != className) {
manager = (LogManager) getInstanceByClass(className);
}
@@ -256,7 +223,7 @@
Logger root = new Logger("", null); //$NON-NLS-1$
root.setLevel(Level.INFO);
Logger.global.setParent(root);
-
+
manager.addLogger(root);
manager.addLogger(Logger.global);
return null;
@@ -290,11 +257,6 @@
}
/*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
- /*
* Package private utilities Returns the line separator of the underlying
* OS.
*/
@@ -307,7 +269,7 @@
* that it is trusted to modify the configuration for logging framework. If
* the check passes, just return, otherwise {@code SecurityException}
* will be thrown.
- *
+ *
* @throws SecurityException
* if there is a security manager in operation and the invoker
* of this method does not have the required security permission
@@ -330,7 +292,7 @@
* unexpectedly garbage collected it is necessary for <i>applications</i>
* to maintain references to them.
* </p>
- *
+ *
* @param logger
* the logger to be added.
* @return true if the given logger is added into the namespace
@@ -347,7 +309,6 @@
return true;
}
-
private void addToFamilyTree(Logger logger, String name) {
Logger parent = null;
// find parent
@@ -359,8 +320,8 @@
if (parent != null) {
logger.internalSetParent(parent);
break;
- } else if (getProperty(parentName+".level") != null || //$NON-NLS-1$
- getProperty(parentName+".handlers") != null) { //$NON-NLS-1$
+ } else if (getProperty(parentName + ".level") != null || //$NON-NLS-1$
+ getProperty(parentName + ".handlers") != null) { //$NON-NLS-1$
parent = Logger.getLogger(parentName);
logger.internalSetParent(parent);
break;
@@ -371,16 +332,22 @@
}
// find children
- //TODO: performance can be improved here?
+ // TODO: performance can be improved here?
Collection<Logger> allLoggers = loggers.values();
- for (Logger child : allLoggers) {
+ for (final Logger child : allLoggers) {
Logger oldParent = child.getParent();
if (parent == oldParent
&& (name.length() == 0 || child.getName().startsWith(
name + '.'))) {
- child.setParent(logger);
+ final Logger thisLogger = logger;
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ child.setParent(thisLogger);
+ return null;
+ }
+ });
if (null != oldParent) {
- //-- remove from old parent as the parent has been changed
+ // -- remove from old parent as the parent has been changed
oldParent.removeChild(child);
}
}
@@ -389,7 +356,7 @@
/**
* Get the logger with the given name.
- *
+ *
* @param name
* name of logger
* @return logger with given name, or {@code null} if nothing is found.
@@ -400,7 +367,7 @@
/**
* Get a {@code Enumeration} of all registered logger names.
- *
+ *
* @return enumeration of registered logger names
*/
public synchronized Enumeration<String> getLoggerNames() {
@@ -409,7 +376,7 @@
/**
* Get the global {@code LogManager} instance.
- *
+ *
* @return the global {@code LogManager} instance
*/
public static LogManager getLogManager() {
@@ -418,7 +385,7 @@
/**
* Get the value of property with given name.
- *
+ *
* @param name
* the name of property
* @return the value of property
@@ -433,7 +400,7 @@
* <p>
* Notice : No {@code PropertyChangeEvent} are fired.
* </p>
- *
+ *
* @throws IOException
* if any IO related problems happened.
* @throws SecurityException
@@ -443,19 +410,20 @@
public void readConfiguration() throws IOException {
checkAccess();
// check config class
- String configClassName = System.getProperty(
- "java.util.logging.config.class"); //$NON-NLS-1$
- if (null == configClassName || null == getInstanceByClass(configClassName)) {
- // if config class failed, check config file
- String configFile = System.getProperty(
- "java.util.logging.config.file"); //$NON-NLS-1$
+ String configClassName = System
+ .getProperty("java.util.logging.config.class"); //$NON-NLS-1$
+ if (null == configClassName
+ || null == getInstanceByClass(configClassName)) {
+ // if config class failed, check config file
+ String configFile = System
+ .getProperty("java.util.logging.config.file"); //$NON-NLS-1$
if (null == configFile) {
// if cannot find configFile, use default logging.properties
configFile = new StringBuilder().append(
System.getProperty("java.home")).append(File.separator) //$NON-NLS-1$
.append("lib").append(File.separator).append( //$NON-NLS-1$
- "logging.properties").toString(); //$NON-NLS-1$
+ "logging.properties").toString(); //$NON-NLS-1$
}
InputStream input = null;
@@ -463,7 +431,7 @@
// BEGIN android-removed
// input = new BufferedInputStream(new FileInputStream(configFile));
// END android-removed
-
+
// BEGIN android-added
try {
input = new BufferedInputStream(
@@ -504,13 +472,12 @@
return clazz.newInstance();
} catch (Exception e) {
try {
- Class<?> clazz = Thread.currentThread()
- .getContextClassLoader().loadClass(className);
+ Class<?> clazz = Thread.currentThread().getContextClassLoader()
+ .loadClass(className);
return clazz.newInstance();
} catch (Exception innerE) {
- //logging.20=Loading class "{0}" failed
- System.err.println(Messages.getString(
- "logging.20", className)); //$NON-NLS-1$
+ // logging.20=Loading class "{0}" failed
+ System.err.println(Messages.getString("logging.20", className)); //$NON-NLS-1$
System.err.println(innerE);
return null;
}
@@ -523,7 +490,7 @@
throws IOException {
reset();
props.load(ins);
-
+
// parse property "config" and apply setting
String configs = props.getProperty("config"); //$NON-NLS-1$
if (null != configs) {
@@ -533,27 +500,25 @@
getInstanceByClass(configerName);
}
}
-
+
// set levels for logger
Collection<Logger> allLoggers = loggers.values();
- for(Logger logger : allLoggers){
- String property = props.getProperty(
- logger.getName()+".level"); //$NON-NLS-1$
- if(null != property){
+ for (Logger logger : allLoggers) {
+ String property = props.getProperty(logger.getName() + ".level"); //$NON-NLS-1$
+ if (null != property) {
logger.setLevel(Level.parse(property));
}
}
listeners.firePropertyChange(null, null, null);
}
-
/**
* Re-initialize the properties and configuration from the given
* {@code InputStream}
* <p>
* Notice : No {@code PropertyChangeEvent} are fired.
* </p>
- *
+ *
* @param ins
* the input stream
* @throws IOException
@@ -574,7 +539,7 @@
* level is set to null, except the root logger's level is set to
* {@code Level.INFO}.
* </p>
- *
+ *
* @throws SecurityException
* if security manager exists and it determines that caller does
* not have the required permissions to perform this action.
@@ -583,10 +548,10 @@
checkAccess();
props = new Properties();
Enumeration<String> names = getLoggerNames();
- while(names.hasMoreElements()){
+ while (names.hasMoreElements()) {
String name = names.nextElement();
Logger logger = getLogger(name);
- if(logger != null){
+ if (logger != null) {
logger.reset();
}
}
@@ -599,7 +564,7 @@
/**
* Add a {@code PropertyChangeListener}, which will be invoked when
* the properties are reread.
- *
+ *
* @param l
* the {@code PropertyChangeListener} to be added.
* @throws SecurityException
@@ -607,7 +572,7 @@
* not have the required permissions to perform this action.
*/
public void addPropertyChangeListener(PropertyChangeListener l) {
- if(l == null){
+ if (l == null) {
throw new NullPointerException();
}
checkAccess();
@@ -617,7 +582,7 @@
/**
* Remove a {@code PropertyChangeListener}, do nothing if the given
* listener is not found.
- *
+ *
* @param l
* the {@code PropertyChangeListener} to be removed.
* @throws SecurityException
diff --git a/libcore/logging/src/main/java/java/util/logging/LogRecord.java b/libcore/logging/src/main/java/java/util/logging/LogRecord.java
index b8a98ef..0a8e257 100644
--- a/libcore/logging/src/main/java/java/util/logging/LogRecord.java
+++ b/libcore/logging/src/main/java/java/util/logging/LogRecord.java
@@ -40,9 +40,6 @@
* {@code getSourceClassName} or {@code getSourceMethodName} if they expect to
* use them after passing the {@code LogRecord} object to another thread or
* transmitting it over RMI.
- * </p>
- *
- * @since Android 1.0
*/
public class LogRecord implements Serializable {
@@ -65,70 +62,70 @@
/**
* The logging level.
- *
+ *
* @serial
*/
private Level level;
/**
* The sequence number.
- *
+ *
* @serial
*/
private long sequenceNumber;
/**
* The name of the class that issued the logging call.
- *
+ *
* @serial
*/
private String sourceClassName;
/**
* The name of the method that issued the logging call.
- *
+ *
* @serial
*/
private String sourceMethodName;
/**
* The original message text.
- *
+ *
* @serial
*/
private String message;
/**
* The ID of the thread that issued the logging call.
- *
+ *
* @serial
*/
private int threadID;
/**
* The time that the event occurred, in milliseconds since 1970.
- *
+ *
* @serial
*/
private long millis;
/**
* The associated {@code Throwable} object if any.
- *
+ *
* @serial
*/
private Throwable thrown;
/**
* The name of the source logger.
- *
+ *
* @serial
*/
private String loggerName;
/**
* The name of the resource bundle used to localize the log message.
- *
+ *
* @serial
*/
private String resourceBundleName;
@@ -148,14 +145,13 @@
* sequence property is set to a new unique value, allocated in increasing
* order within the virtual machine. The thread ID is set to a unique value
* for the current thread. All other properties are set to {@code null}.
- *
+ *
* @param level
* the logging level, may not be {@code null}.
* @param msg
* the raw message.
* @throws NullPointerException
* if {@code level} is {@code null}.
- * @since Android 1.0
*/
public LogRecord(Level level, String msg) {
if (null == level) {
@@ -188,9 +184,8 @@
/**
* Gets the logging level.
- *
+ *
* @return the logging level.
- * @since Android 1.0
*/
public Level getLevel() {
return level;
@@ -198,12 +193,11 @@
/**
* Sets the logging level.
- *
+ *
* @param level
* the level to set.
* @throws NullPointerException
* if {@code level} is {@code null}.
- * @since Android 1.0
*/
public void setLevel(Level level) {
if (null == level) {
@@ -215,9 +209,8 @@
/**
* Gets the name of the logger.
- *
+ *
* @return the logger name.
- * @since Android 1.0
*/
public String getLoggerName() {
return loggerName;
@@ -225,10 +218,9 @@
/**
* Sets the name of the logger.
- *
+ *
* @param loggerName
* the logger name to set.
- * @since Android 1.0
*/
public void setLoggerName(String loggerName) {
this.loggerName = loggerName;
@@ -236,9 +228,8 @@
/**
* Gets the raw message.
- *
+ *
* @return the raw message, may be {@code null}.
- * @since Android 1.0
*/
public String getMessage() {
return message;
@@ -248,10 +239,9 @@
* Sets the raw message. When this record is formatted by a logger that has
* a localization resource bundle that contains an entry for {@code message},
* then the raw message is replaced with its localized version.
- *
+ *
* @param message
* the raw message to set, may be {@code null}.
- * @since Android 1.0
*/
public void setMessage(String message) {
this.message = message;
@@ -259,9 +249,8 @@
/**
* Gets the time when this event occurred, in milliseconds since 1970.
- *
+ *
* @return the time when this event occurred, in milliseconds since 1970.
- * @since Android 1.0
*/
public long getMillis() {
return millis;
@@ -269,10 +258,9 @@
/**
* Sets the time when this event occurred, in milliseconds since 1970.
- *
+ *
* @param millis
* the time when this event occurred, in milliseconds since 1970.
- * @since Android 1.0
*/
public void setMillis(long millis) {
this.millis = millis;
@@ -280,10 +268,9 @@
/**
* Gets the parameters.
- *
+ *
* @return the array of parameters or {@code null} if there are no
* parameters.
- * @since Android 1.0
*/
public Object[] getParameters() {
return parameters;
@@ -291,10 +278,9 @@
/**
* Sets the parameters.
- *
+ *
* @param parameters
* the array of parameters to set, may be {@code null}.
- * @since Android 1.0
*/
public void setParameters(Object[] parameters) {
this.parameters = parameters;
@@ -303,21 +289,20 @@
/**
* Gets the resource bundle used to localize the raw message during
* formatting.
- *
+ *
* @return the associated resource bundle, {@code null} if none is
* available or the message is not localizable.
- * @since Android 1.0
*/
public ResourceBundle getResourceBundle() {
return resourceBundle;
}
/**
- * Sets the resource bundle.
- *
+ * Sets the resource bundle used to localize the raw message during
+ * formatting.
+ *
* @param resourceBundle
* the resource bundle to set, may be {@code null}.
- * @since Android 1.0
*/
public void setResourceBundle(ResourceBundle resourceBundle) {
this.resourceBundle = resourceBundle;
@@ -325,10 +310,9 @@
/**
* Gets the name of the resource bundle.
- *
+ *
* @return the name of the resource bundle, {@code null} if none is
* available or the message is not localizable.
- * @since Android 1.0
*/
public String getResourceBundleName() {
return resourceBundleName;
@@ -336,10 +320,9 @@
/**
* Sets the name of the resource bundle.
- *
+ *
* @param resourceBundleName
* the name of the resource bundle to set.
- * @since Android 1.0
*/
public void setResourceBundleName(String resourceBundleName) {
this.resourceBundleName = resourceBundleName;
@@ -347,9 +330,8 @@
/**
* Gets the sequence number.
- *
+ *
* @return the sequence number.
- * @since Android 1.0
*/
public long getSequenceNumber() {
return sequenceNumber;
@@ -359,10 +341,9 @@
* Sets the sequence number. It is usually not necessary to call this method
* to change the sequence number because the number is allocated when this
* instance is constructed.
- *
+ *
* @param sequenceNumber
* the sequence number to set.
- * @since Android 1.0
*/
public void setSequenceNumber(long sequenceNumber) {
this.sequenceNumber = sequenceNumber;
@@ -371,9 +352,8 @@
/**
* Gets the name of the class that is the source of this log record. This
* information can be changed, may be {@code null} and is untrusted.
- *
+ *
* @return the name of the source class of this log record (possiblity {@code null})
- * @since Android 1.0
*/
public String getSourceClassName() {
initSource();
@@ -394,7 +374,8 @@
break FINDLOG;
}
}
- while(++i<elements.length && elements[i].getClassName().equals(current)) {
+ while (++i < elements.length
+ && elements[i].getClassName().equals(current)) {
// do nothing
}
if (i < elements.length) {
@@ -407,11 +388,10 @@
/**
* Sets the name of the class that is the source of this log record.
- *
+ *
* @param sourceClassName
* the name of the source class of this log record, may be
* {@code null}.
- * @since Android 1.0
*/
public void setSourceClassName(String sourceClassName) {
sourceInited = true;
@@ -420,9 +400,8 @@
/**
* Gets the name of the method that is the source of this log record.
- *
+ *
* @return the name of the source method of this log record.
- * @since Android 1.0
*/
public String getSourceMethodName() {
initSource();
@@ -431,11 +410,10 @@
/**
* Sets the name of the method that is the source of this log record.
- *
+ *
* @param sourceMethodName
* the name of the source method of this log record, may be
* {@code null}.
- * @since Android 1.0
*/
public void setSourceMethodName(String sourceMethodName) {
sourceInited = true;
@@ -448,9 +426,8 @@
* <p>
* Notice : the ID doesn't necessary map the OS thread ID
* </p>
- *
+ *
* @return the ID of the thread originating this log record.
- * @since Android 1.0
*/
public int getThreadID() {
return threadID;
@@ -458,10 +435,9 @@
/**
* Sets the ID of the thread originating this log record.
- *
+ *
* @param threadID
* the new ID of the thread originating this log record.
- * @since Android 1.0
*/
public void setThreadID(int threadID) {
this.threadID = threadID;
@@ -469,9 +445,8 @@
/**
* Gets the {@code Throwable} object associated with this log record.
- *
+ *
* @return the {@code Throwable} object associated with this log record.
- * @since Android 1.0
*/
public Throwable getThrown() {
return thrown;
@@ -479,11 +454,10 @@
/**
* Sets the {@code Throwable} object associated with this log record.
- *
+ *
* @param thrown
* the new {@code Throwable} object to associate with this log
* record.
- * @since Android 1.0
*/
public void setThrown(Throwable thrown) {
this.thrown = thrown;
@@ -514,12 +488,13 @@
in.defaultReadObject();
byte major = in.readByte();
byte minor = in.readByte();
- //only check MAJOR version
+ // only check MAJOR version
if (major != MAJOR) {
// logging.5=Different version - {0}.{1}
- throw new IOException(Messages.getString("logging.5", major, minor)); //$NON-NLS-1$
+ throw new IOException(Messages.getString("logging.5", //$NON-NLS-1$
+ Byte.valueOf(major), Byte.valueOf(minor)));
}
-
+
int length = in.readInt();
if (length >= 0) {
parameters = new Object[length];
diff --git a/libcore/logging/src/main/java/java/util/logging/Logger.java b/libcore/logging/src/main/java/java/util/logging/Logger.java
index cd88ca0..fe124d3 100644
--- a/libcore/logging/src/main/java/java/util/logging/Logger.java
+++ b/libcore/logging/src/main/java/java/util/logging/Logger.java
@@ -24,7 +24,6 @@
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
-import java.util.StringTokenizer;
import org.apache.harmony.logging.internal.nls.Messages;
@@ -39,7 +38,6 @@
* namespace hierarchy managed by a log manager. The naming convention is
* usually the same as java package's naming convention, that is using
* dot-separated strings. Anonymous loggers do not belong to any namespace.
- * </p>
* <p>
* Loggers "inherit" log level setting from their parent if their own level is
* set to {@code null}. This is also true for the resource bundle. The logger's
@@ -49,36 +47,28 @@
* context, "inherit" only means that "behavior" is inherited. The internal
* field values will not change, for example, {@code getLevel()} still returns
* {@code null}.
- * </p>
* <p>
* When loading a given resource bundle, the logger first tries to use the
* context classloader. If that fails, it tries the system classloader. And if
* that still fails, it searches up the class stack and uses each class's
* classloader to try to locate the resource bundle.
- * </p>
* <p>
* Some log methods accept log requests that do not specify the source class and
* source method. In these cases, the logging framework will automatically infer
* the calling class and method, but this is not guaranteed to be accurate.
- * </p>
* <p>
* Once a {@code LogRecord} object has been passed into the logging framework,
* it is owned by the logging framework and the client applications should not
* use it any longer.
- * </p>
* <p>
* All methods of this class are thread-safe.
- * </p>
- *
+ *
* @see LogManager
- * @since Android 1.0
*/
public class Logger {
/**
* The global logger is provided as convenience for casual use.
- *
- * @since Android 1.0
*/
public final static Logger global = new Logger("global", null); //$NON-NLS-1$
@@ -116,27 +106,19 @@
private boolean isNamed;
private List<Logger> childs;
-
+
private LogManager manager;
// BEGIN android-changed
private volatile boolean handlerInited;
// END android-changed
-
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
-
/**
* Constructs a {@code Logger} object with the supplied name and resource
* bundle name; {@code notifiyParentHandlers} is set to {@code true}.
* <p>
- * Notice : Loggers use a naming hierarchy. Thus "z.x.y" is a child of "z.x".
- * </p>
- *
+ * Notice : Loggers use a naming hierarchy. Thus "z.x.y" is a child of "z.x".
+ *
* @param name
* the name of this logger, may be {@code null} for anonymous
* loggers.
@@ -145,7 +127,6 @@
* messages, may be {@code null}.
* @throws MissingResourceException
* if the specified resource bundle can not be loaded.
- * @since Android 1.0
*/
protected Logger(String name, String resourceBundleName) {
// try to load the specified resource bundle first
@@ -164,24 +145,24 @@
// any logger is not anonymous by default
this.isNamed = true;
- //-- 'null' means that level will be inherited from parent (see getLevel)
- //-- Level.INFO is default level if we don't set it. It will be
- //-- changed to parent level or to configLevel after adding to the
- //-- family tree. As of this, actually, setting to Level.INFO is
- //-- not needed here.
+ // -- 'null' means that level will be inherited from parent (see
+ // getLevel)
+ // -- Level.INFO is default level if we don't set it. It will be
+ // -- changed to parent level or to configLevel after adding to the
+ // -- family tree. As of this, actually, setting to Level.INFO is
+ // -- not needed here.
this.levelObjVal = null;
this.levelIntVal = Level.INFO.intValue();
}
- //-- should be called under the lm lock
+ // -- should be called under the lm lock
private void setLevelImpl(Level newLevel) {
// update levels for the whole hierarchy
int oldVal = levelIntVal;
levelObjVal = newLevel;
if (null == newLevel) {
- levelIntVal = null != parent
- ? parent.levelIntVal
- : Level.INFO.intValue();
+ levelIntVal = null != parent ? parent.levelIntVal : Level.INFO
+ .intValue();
} else {
levelIntVal = newLevel.intValue();
}
@@ -190,7 +171,7 @@
}
}
- //-- should be called under the lm lock
+ // -- should be called under the lm lock
private void forceChildsToInherit() {
for (Logger child : childs) {
if (null == child.levelObjVal) { // should inherit
@@ -199,15 +180,9 @@
}
}
- /*
- * -------------------------------------------------------------------
- * Methods
- * -------------------------------------------------------------------
- */
-
/**
* Load the specified resource bundle, use privileged code.
- *
+ *
* @param resourceBundleName
* the name of the resource bundle to load, cannot be {@code null}.
* @return the loaded resource bundle.
@@ -216,8 +191,8 @@
*/
static ResourceBundle loadResourceBundle(String resourceBundleName) {
// try context class loader to load the resource
- ClassLoader cl = AccessController.doPrivileged(
- new PrivilegedAction<ClassLoader>() {
+ ClassLoader cl = AccessController
+ .doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
@@ -231,12 +206,11 @@
}
}
// try system class loader to load the resource
- cl = AccessController.doPrivileged(
- new PrivilegedAction<ClassLoader>() {
- public ClassLoader run() {
- return ClassLoader.getSystemClassLoader();
- }
- });
+ cl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
+ public ClassLoader run() {
+ return ClassLoader.getSystemClassLoader();
+ }
+ });
if (null != cl) {
try {
return ResourceBundle.getBundle(resourceBundleName, Locale
@@ -257,8 +231,8 @@
for (int i = 1; i < classes.length; i++) {
final int index = i;
try {
- cl = AccessController.doPrivileged(
- new PrivilegedAction<ClassLoader>() {
+ cl = AccessController
+ .doPrivileged(new PrivilegedAction<ClassLoader>() {
public ClassLoader run() {
return classes[index].getClassLoader();
}
@@ -274,7 +248,7 @@
}
// logging.8=Failed to load the specified resource bundle "{0}".
throw new MissingResourceException(Messages.getString("logging.8", //$NON-NLS-1$
- resourceBundleName), resourceBundleName, null);
+ resourceBundleName), resourceBundleName, null);
}
/**
@@ -284,10 +258,8 @@
* <p>
* The anonymous loggers' parent is set to be the root logger. This way it
* inherits the default logging level and handlers from the root logger.
- * </p>
- *
+ *
* @return a new instance of anonymous logger.
- * @since Android 1.0
*/
public static Logger getAnonymousLogger() {
return getAnonymousLogger(null);
@@ -300,14 +272,12 @@
* <p>
* The anonymous loggers' parent is set to be the root logger. This way it
* inherits default logging level and handlers from the root logger.
- * </p>
- *
+ *
* @param resourceBundleName
* the name of the resource bundle used to localize log messages.
* @return a new instance of anonymous logger.
* @throws MissingResourceException
* if the specified resource bundle can not be loaded.
- * @since Android 1.0
*/
public static Logger getAnonymousLogger(String resourceBundleName) {
final Logger l = new Logger(null, resourceBundleName);
@@ -324,26 +294,24 @@
private static void updateResourceBundle(Logger l, String resourceBundleName) {
synchronized (l) {
if (null == l.getResourceBundleName()) {
- if(null == resourceBundleName){
+ if (null == resourceBundleName) {
return;
}
/*
- * load the resource bundle if none is specified
- * before
+ * load the resource bundle if none is specified before
*/
l.resBundle = loadResourceBundle(resourceBundleName);
l.resBundleName = resourceBundleName;
} else if (!l.getResourceBundleName().equals(resourceBundleName)) {
/*
- * throw exception if the specified resource bundles
- * are inconsistent with each other, i.e., different
- * names
+ * throw exception if the specified resource bundles are
+ * inconsistent with each other, i.e., different names
*/
- // logging.9=The specified resource bundle name "{0}" is
+ // logging.9=The specified resource bundle name "{0}" is
// inconsistent with the existing one "{1}".
throw new IllegalArgumentException(Messages.getString(
"logging.9", //$NON-NLS-1$
- resourceBundleName, l.getResourceBundleName()));
+ resourceBundleName, l.getResourceBundleName()));
}
}
}
@@ -378,11 +346,12 @@
* Gets a named logger. The returned logger may already exist or may be
* newly created. In the latter case, its level will be set to the
* configured level according to the {@code LogManager}'s properties.
- *
+ *
* @param name
* the name of the logger to get, cannot be {@code null}.
* @return a named logger.
- * @since Android 1.0
+ * @throws MissingResourceException
+ * If the specified resource bundle can not be loaded.
*/
public static Logger getLogger(String name) {
return getLoggerWithRes(name, null, false);
@@ -391,7 +360,7 @@
/**
* Gets a named logger associated with the supplied resource bundle. The
* resource bundle will be used to localize logging messages.
- *
+ *
* @param name
* the name of the logger to get, cannot be {@code null}.
* @param resourceBundleName
@@ -403,7 +372,6 @@
* @throws MissingResourceException
* if the name of the resource bundle cannot be found.
* @return a named logger.
- * @since Android 1.0
*/
public static Logger getLogger(String name, String resourceBundleName) {
return getLoggerWithRes(name, resourceBundleName, true);
@@ -412,13 +380,12 @@
/**
* Adds a handler to this logger. The {@code name} will be fed with log
* records received by this logger.
- *
+ *
* @param handler
* the handler object to add, cannot be {@code null}.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void addHandler(Handler handler) {
if (null == handler) {
@@ -430,25 +397,25 @@
LogManager.getLogManager().checkAccess();
}
initHandler();
- synchronized(this){
+ synchronized (this) {
this.handlers.add(handler);
}
}
-
+
/*
- * Be cautious to avoid deadlock when using this method, it gets lock on manager
- * at first, and then gets lock on this Logger, so any methods should not hold
- * lock on this Logger when invoking this method.
+ * Be cautious to avoid deadlock when using this method, it gets lock on manager
+ * at first, and then gets lock on this Logger, so any methods should not hold
+ * lock on this Logger when invoking this method.
*/
private void initHandler() {
- if(!handlerInited){
+ if (!handlerInited) {
synchronized (this) {
if (!handlerInited) {
// BEGIN android-added
/*
* Force LogManager to be initialized, since its
* class init code performs necessary one-time setup.
- */
+ */
LogManager.getLogManager();
// END android-added
if (handlers == null) {
@@ -463,26 +430,27 @@
if (null == handlerStr) {
return;
}
- StringTokenizer st = new StringTokenizer(handlerStr, " "); //$NON-NLS-1$
- while (st.hasMoreTokens()) {
- String handlerName = st.nextToken();
- // BEGIN android-changed
- // deal with non-existing handler
- try {
- Handler handler = (Handler) LogManager
- .getInstanceByClass(handlerName);
- handlers.add(handler);
- String level = manager.getProperty(handlerName
- + ".level"); //$NON-NLS-1$
- if (null != level) {
- handler.setLevel(Level.parse(level));
- }
- } catch (Exception ex) {
- ex.printStackTrace();
- }
- // END android-changed
+ String[] strs = handlerStr.split(",|\\s"); //$NON-NLS-1$
+ for (int i = 0; i < strs.length; i++) {
+ String handlerName = strs[i];
+ if (handlerName.equals("")) { //$NON-NLS-1$
+ continue;
}
- handlerInited = true;
+ // BEGIN android-changed
+ // deal with non-existing handler
+ try {
+ Handler handler = (Handler) LogManager.getInstanceByClass(handlerName);
+ handlers.add(handler);
+ String level = manager.getProperty(handlerName + ".level"); //$NON-NLS-1$
+ if (null != level) {
+ handler.setLevel(Level.parse(level));
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ // END android-changed
+ }
+ handlerInited = true;
}
}
}
@@ -490,13 +458,12 @@
/**
* Gets all the handlers associated with this logger.
- *
+ *
* @return an array of all the handlers associated with this logger.
- * @since Android 1.0
*/
public Handler[] getHandlers() {
initHandler();
- synchronized(this){
+ synchronized (this) {
return handlers.toArray(new Handler[handlers.size()]);
}
}
@@ -504,13 +471,12 @@
/**
* Removes a handler from this logger. If the specified handler does not
* exist then this method has no effect.
- *
+ *
* @param handler
* the handler to be removed.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void removeHandler(Handler handler) {
// Anonymous loggers can always remove handlers
@@ -521,16 +487,15 @@
return;
}
initHandler();
- synchronized(this){
+ synchronized (this) {
this.handlers.remove(handler);
}
}
/**
* Gets the filter used by this logger.
- *
+ *
* @return the filter used by this logger, may be {@code null}.
- * @since Android 1.0
*/
public Filter getFilter() {
return this.filter;
@@ -538,13 +503,12 @@
/**
* Sets the filter used by this logger.
- *
+ *
* @param newFilter
* the filter to set, may be {@code null}.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setFilter(Filter newFilter) {
// Anonymous loggers can always set the filter
@@ -557,9 +521,8 @@
/**
* Gets the logging level of this logger. A {@code null} level indicates
* that this logger inherits its parent's level.
- *
+ *
* @return the logging level of this logger.
- * @since Android 1.0
*/
public Level getLevel() {
return levelObjVal;
@@ -568,13 +531,12 @@
/**
* Sets the logging level for this logger. A {@code null} level indicates
* that this logger will inherit its parent's level.
- *
+ *
* @param newLevel
* the logging level to set.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setLevel(Level newLevel) {
// Anonymous loggers can always set the level
@@ -590,10 +552,9 @@
* Gets the flag which indicates whether to use the handlers of this
* logger's parent to publish incoming log records, potentially recursively
* up the namespace.
- *
+ *
* @return {@code true} if set to use parent's handlers, {@code false}
* otherwise.
- * @since Android 1.0
*/
public boolean getUseParentHandlers() {
return this.notifyParentHandlers;
@@ -602,13 +563,12 @@
/**
* Sets the flag which indicates whether to use the handlers of this
* logger's parent, potentially recursively up the namespace.
- *
+ *
* @param notifyParentHandlers
* the new flag indicating whether to use the parent's handlers.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setUseParentHandlers(boolean notifyParentHandlers) {
// Anonymous loggers can always set the useParentHandlers flag
@@ -621,9 +581,8 @@
/**
* Gets the nearest parent of this logger in the namespace, a {@code null}
* value will be returned if called on the root logger.
- *
+ *
* @return the parent of this logger in the namespace.
- * @since Android 1.0
*/
public Logger getParent() {
return parent;
@@ -633,14 +592,14 @@
* Sets the parent of this logger in the namespace. This method should
* usually be used by the {@code LogManager} object only. This method does
* not check security.
- *
+ *
* @param newParent
* the parent logger to set.
- * @since Android 1.0
*/
void internalSetParent(Logger newParent) {
- //All hierarchy related modifications should get LogManager lock at first
- synchronized(LogManager.getLogManager()){
+ // All hierarchy related modifications should get LogManager lock at
+ // first
+ synchronized (LogManager.getLogManager()) {
parent = newParent;
// -- update level after setting a parent.
// -- if level == null we should inherit the parent's level
@@ -654,13 +613,12 @@
/**
* Sets the parent of this logger in the namespace. This method should be
* used by the {@code LogManager} object only.
- *
+ *
* @param parent
* the parent logger to set.
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
public void setParent(Logger parent) {
if (null == parent) {
@@ -680,12 +638,10 @@
childs.remove(child);
}
-
/**
* Gets the name of this logger, {@code null} for anonymous loggers.
- *
+ *
* @return the name of this logger.
- * @since Android 1.0
*/
public String getName() {
return this.name;
@@ -695,9 +651,8 @@
* Gets the loaded resource bundle used by this logger to localize logging
* messages. If the value is {@code null}, the parent's resource bundle will be
* inherited.
- *
+ *
* @return the loaded resource bundle used by this logger.
- * @since Android 1.0
*/
public ResourceBundle getResourceBundle() {
return this.resBundle;
@@ -707,9 +662,8 @@
* Gets the name of the loaded resource bundle used by this logger to
* localize logging messages. If the value is {@code null}, the parent's resource
* bundle name will be inherited.
- *
+ *
* @return the name of the loaded resource bundle used by this logger.
- * @since Android 1.0
*/
public String getResourceBundleName() {
return this.resBundleName;
@@ -734,12 +688,11 @@
* Determines whether this logger will actually log messages of the
* specified level. The effective level used to do the determination may be
* inherited from its parent. The default level is {@code Level.INFO}.
- *
+ *
* @param l
* the level to check.
* @return {@code true} if this logger will actually log this level,
* otherwise {@code false}.
- * @since Android 1.0
*/
public boolean isLoggable(Level l) {
return internalIsLoggable(l);
@@ -775,12 +728,11 @@
* Logs a message indicating that a method has been entered. A log record
* with log level {@code Level.FINER}, log message "ENTRY", the specified
* source class name and source method name is submitted for logging.
- *
+ *
* @param sourceClass
* the calling class name.
* @param sourceMethod
* the method name.
- * @since Android 1.0
*/
public void entering(String sourceClass, String sourceMethod) {
if (internalIsLoggable(Level.FINER)) {
@@ -798,14 +750,13 @@
* with log level {@code Level.FINER}, log message "ENTRY", the specified
* source class name, source method name and one parameter is submitted for
* logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param param
* the parameter for the method call.
- * @since Android 1.0
*/
public void entering(String sourceClass, String sourceMethod, Object param) {
if (internalIsLoggable(Level.FINER)) {
@@ -824,14 +775,13 @@
* with log level {@code Level.FINER}, log message "ENTRY", the specified
* source class name, source method name and array of parameters is
* submitted for logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param params
* an array of parameters for the method call.
- * @since Android 1.0
*/
public void entering(String sourceClass, String sourceMethod,
Object[] params) {
@@ -858,12 +808,11 @@
* Logs a message indicating that a method is exited. A log record with log
* level {@code Level.FINER}, log message "RETURN", the specified source
* class name and source method name is submitted for logging.
- *
+ *
* @param sourceClass
* the calling class name.
* @param sourceMethod
* the method name.
- * @since Android 1.0
*/
public void exiting(String sourceClass, String sourceMethod) {
if (internalIsLoggable(Level.FINER)) {
@@ -880,14 +829,13 @@
* Logs a message indicating that a method is exited. A log record with log
* level {@code Level.FINER}, log message "RETURN", the specified source
* class name, source method name and return value is submitted for logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param result
* the return value of the method call.
- * @since Android 1.0
*/
public void exiting(String sourceClass, String sourceMethod, Object result) {
if (internalIsLoggable(Level.FINER)) {
@@ -906,14 +854,13 @@
* log level {@code Level.FINER}, log message "THROW", the specified source
* class name, source method name and the {@code Throwable} object is
* submitted for logging.
- *
+ *
* @param sourceClass
* the source class name.
* @param sourceMethod
* the source method name.
* @param thrown
* the {@code Throwable} object.
- * @since Android 1.0
*/
public void throwing(String sourceClass, String sourceMethod,
Throwable thrown) {
@@ -931,10 +878,9 @@
/**
* Logs a message of level {@code Level.SEVERE}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void severe(String msg) {
if (internalIsLoggable(Level.SEVERE)) {
@@ -948,10 +894,9 @@
/**
* Logs a message of level {@code Level.WARNING}; the message is
* transmitted to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void warning(String msg) {
if (internalIsLoggable(Level.WARNING)) {
@@ -965,10 +910,9 @@
/**
* Logs a message of level {@code Level.INFO}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void info(String msg) {
if (internalIsLoggable(Level.INFO)) {
@@ -982,10 +926,9 @@
/**
* Logs a message of level {@code Level.CONFIG}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void config(String msg) {
if (internalIsLoggable(Level.CONFIG)) {
@@ -999,10 +942,9 @@
/**
* Logs a message of level {@code Level.FINE}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void fine(String msg) {
if (internalIsLoggable(Level.FINE)) {
@@ -1016,10 +958,9 @@
/**
* Logs a message of level {@code Level.FINER}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void finer(String msg) {
if (internalIsLoggable(Level.FINER)) {
@@ -1033,10 +974,9 @@
/**
* Logs a message of level {@code Level.FINEST}; the message is transmitted
* to all subscribed handlers.
- *
+ *
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void finest(String msg) {
if (internalIsLoggable(Level.FINEST)) {
@@ -1050,12 +990,11 @@
/**
* Logs a message of the specified level. The message is transmitted to all
* subscribed handlers.
- *
+ *
* @param logLevel
* the level of the specified message.
* @param msg
* the message to log.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg) {
if (internalIsLoggable(logLevel)) {
@@ -1069,14 +1008,13 @@
/**
* Logs a message of the specified level with the supplied parameter. The
* message is then transmitted to all subscribed handlers.
- *
+ *
* @param logLevel
* the level of the given message.
* @param msg
* the message to log.
* @param param
* the parameter associated with the event that is logged.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg, Object param) {
if (internalIsLoggable(logLevel)) {
@@ -1091,14 +1029,13 @@
/**
* Logs a message of the specified level with the supplied parameter array.
* The message is then transmitted to all subscribed handlers.
- *
+ *
* @param logLevel
* the level of the given message
* @param msg
* the message to log.
* @param params
* the parameter array associated with the event that is logged.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg, Object[] params) {
if (internalIsLoggable(logLevel)) {
@@ -1113,7 +1050,7 @@
/**
* Logs a message of the specified level with the supplied {@code Throwable}
* object. The message is then transmitted to all subscribed handlers.
- *
+ *
* @param logLevel
* the level of the given message.
* @param msg
@@ -1121,7 +1058,6 @@
* @param thrown
* the {@code Throwable} object associated with the event that is
* logged.
- * @since Android 1.0
*/
public void log(Level logLevel, String msg, Throwable thrown) {
if (internalIsLoggable(logLevel)) {
@@ -1144,10 +1080,9 @@
* logging action, subclasses of this class can override this method to
* catch all logging activities.
* </p>
- *
+ *
* @param record
* the log record to be logged.
- * @since Android 1.0
*/
public void log(LogRecord record) {
if (internalIsLoggable(record.getLevel())) {
@@ -1158,8 +1093,7 @@
}
initHandler();
/*
- * call the handlers of this logger, throw any exception that
- * occurs
+ * call the handlers of this logger, throw any exception that occurs
*/
Handler[] allHandlers = getHandlers();
for (Handler element : allHandlers) {
@@ -1182,7 +1116,7 @@
/**
* Logs a message of the given level with the specified source class name
* and source method name.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1191,7 +1125,6 @@
* the source method name.
* @param msg
* the message to be logged.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg) {
@@ -1208,7 +1141,7 @@
/**
* Logs a message of the given level with the specified source class name,
* source method name and parameter.
- *
+ *
* @param logLevel
* the level of the given message
* @param sourceClass
@@ -1219,7 +1152,6 @@
* the message to be logged
* @param param
* the parameter associated with the event that is logged.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg, Object param) {
@@ -1237,7 +1169,7 @@
/**
* Logs a message of the given level with the specified source class name,
* source method name and parameter array.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1248,7 +1180,6 @@
* the message to be logged.
* @param params
* the parameter array associated with the event that is logged.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg, Object[] params) {
@@ -1266,7 +1197,7 @@
/**
* Logs a message of the given level with the specified source class name,
* source method name and {@code Throwable} object.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1277,7 +1208,6 @@
* the message to be logged.
* @param thrown
* the {@code Throwable} object.
- * @since Android 1.0
*/
public void logp(Level logLevel, String sourceClass, String sourceMethod,
String msg, Throwable thrown) {
@@ -1297,7 +1227,7 @@
* and source method name, using the given resource bundle to localize the
* message. If {@code bundleName} is null, the empty string or not valid then
* the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1308,7 +1238,6 @@
* the name of the resource bundle used to localize the message.
* @param msg
* the message to be logged.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg) {
@@ -1334,7 +1263,7 @@
* source method name and parameter, using the given resource bundle to
* localize the message. If {@code bundleName} is null, the empty string
* or not valid then the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1347,7 +1276,6 @@
* the message to be logged.
* @param param
* the parameter associated with the event that is logged.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg, Object param) {
@@ -1374,7 +1302,7 @@
* source method name and parameter array, using the given resource bundle
* to localize the message. If {@code bundleName} is null, the empty string
* or not valid then the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message.
* @param sourceClass
@@ -1387,7 +1315,6 @@
* the message to be logged.
* @param params
* the parameter array associated with the event that is logged.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg, Object[] params) {
@@ -1414,7 +1341,7 @@
* source method name and {@code Throwable} object, using the given resource
* bundle to localize the message. If {@code bundleName} is null, the empty
* string or not valid then the message is not localized.
- *
+ *
* @param logLevel
* the level of the given message
* @param sourceClass
@@ -1427,7 +1354,6 @@
* the message to be logged.
* @param thrown
* the {@code Throwable} object.
- * @since Android 1.0
*/
public void logrb(Level logLevel, String sourceClass, String sourceMethod,
String bundleName, String msg, Throwable thrown) {
@@ -1459,25 +1385,30 @@
}
void setManager(LogManager manager) {
- if(this.manager != manager){
+ if (this.manager != manager) {
this.manager = manager;
- handlerInited = false;
+ handlerInited = false;
}
- //init level here, but let handlers be for lazy loading
- String configedLevel = manager.getProperty(name+ ".level"); //$NON-NLS-1$
+ // init level here, but let handlers be for lazy loading
+ final String configedLevel = manager.getProperty(name + ".level"); //$NON-NLS-1$
if (null != configedLevel) {
try {
- setLevel(Level.parse(configedLevel));
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ setLevel(Level.parse(configedLevel));
+ return null;
+ }
+ });
} catch (IllegalArgumentException e) {
- //ignore
+ // ignore
}
- }
+ }
}
synchronized void reset() {
levelObjVal = null;
levelIntVal = Level.INFO.intValue();
- if(handlers != null){
+ if (handlers != null) {
for (Handler element : handlers) {
// close all handlers, when unknown exceptions happen,
// ignore them and go on
@@ -1492,4 +1423,3 @@
handlerInited = false;
}
}
-
diff --git a/libcore/logging/src/main/java/java/util/logging/LoggingMXBean.java b/libcore/logging/src/main/java/java/util/logging/LoggingMXBean.java
index f6b49a6..18cc4cc 100644
--- a/libcore/logging/src/main/java/java/util/logging/LoggingMXBean.java
+++ b/libcore/logging/src/main/java/java/util/logging/LoggingMXBean.java
@@ -25,29 +25,28 @@
* The ObjectName for identifying the {@code LoggingMXBean} in a bean server is
* {@link LogManager#LOGGING_MXBEAN_NAME}.
* </p>
- *
- * @since Android 1.0
+ *
+ * @since 1.5
*/
public interface LoggingMXBean {
+
/**
* Gets the string value of the logging level of a logger. An empty string
* is returned when the logger's level is defined by its parent. A
* {@code null} is returned if the specified logger does not exist.
- *
+ *
* @param loggerName
* the name of the logger lookup.
* @return a {@code String} if the logger is found, otherwise {@code null}.
* @see Level#getName()
- * @since Android 1.0
*/
String getLoggerLevel(String loggerName);
/**
* Gets a list of all currently registered logger names. This is performed
* using the {@link LogManager#getLoggerNames()}.
- *
+ *
* @return a list of logger names.
- * @since Android 1.0
*/
List<String> getLoggerNames();
@@ -55,18 +54,17 @@
* Gets the name of the parent logger of a logger. If the logger doesn't
* exist then {@code null} is returned. If the logger is the root logger,
* then an empty {@code String} is returned.
- *
+ *
* @param loggerName
* the name of the logger to lookup.
* @return a {@code String} if the logger was found, otherwise {@code null}.
- * @since Android 1.0
*/
String getParentLoggerName(String loggerName);
/**
* Sets the log level of a logger. LevelName set to {@code null} means the
* level is inherited from the nearest non-null ancestor.
- *
+ *
* @param loggerName
* the name of the logger to set the level on, which must not be
* {@code null}.
@@ -79,7 +77,6 @@
* if a security manager exists and the caller doesn't have
* LoggingPermission("control").
* @see Level#parse(String)
- * @since Android 1.0
*/
void setLoggerLevel(String loggerName, String levelName);
}
diff --git a/libcore/logging/src/main/java/java/util/logging/LoggingPermission.java b/libcore/logging/src/main/java/java/util/logging/LoggingPermission.java
index fb6d4f8..aa41a2c 100644
--- a/libcore/logging/src/main/java/java/util/logging/LoggingPermission.java
+++ b/libcore/logging/src/main/java/java/util/logging/LoggingPermission.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.io.Serializable;
@@ -27,20 +26,12 @@
/**
* The permission required to control the logging when run with a
* {@code SecurityManager}.
- *
*/
public final class LoggingPermission extends BasicPermission implements Guard,
Serializable {
- //for serialization compatibility with J2SE 1.4.2
- private static final long serialVersionUID =63564341580231582L;
-
-
- /*
- * -------------------------------------------------------------------
- * Constructors
- * -------------------------------------------------------------------
- */
+ // for serialization compatibility with J2SE 1.4.2
+ private static final long serialVersionUID = 63564341580231582L;
/**
* Constructs a {@code LoggingPermission} object required to control the
@@ -50,7 +41,7 @@
* and depends on the security policy file, therefore programmers shouldn't
* normally use them directly.
* </p>
- *
+ *
* @param name
* currently must be "control".
* @param actions
@@ -71,4 +62,3 @@
}
}
-
diff --git a/libcore/logging/src/main/java/java/util/logging/MemoryHandler.java b/libcore/logging/src/main/java/java/util/logging/MemoryHandler.java
index c1e8670..3312083 100644
--- a/libcore/logging/src/main/java/java/util/logging/MemoryHandler.java
+++ b/libcore/logging/src/main/java/java/util/logging/MemoryHandler.java
@@ -22,7 +22,6 @@
import org.apache.harmony.logging.internal.nls.Messages;
-
/**
* A {@code Handler} put the description of log events into a cycled memory
* buffer.
@@ -30,68 +29,61 @@
* Mostly this {@code MemoryHandler} just puts the given {@code LogRecord} into
* the internal buffer and doesn't perform any formatting or any other process.
* When the buffer is full, the earliest buffered records will be discarded.
- * </p>
* <p>
* Every {@code MemoryHandler} has a target handler, and push action can be
* triggered so that all buffered records will be output to the target handler
* and normally the latter will publish the records. After the push action, the
* buffer will be cleared.
- * </p>
* <p>
- * The push action can be triggered in three ways:
- * <ul>
- * <li>The push method is called explicitly</li>
- * <li>When a new {@code LogRecord} is put into the internal buffer, and it has
- * a level which is not less than the specified push level.</li>
- * <li>A subclass extends this {@code MemoryHandler} and call push method
- * implicitly according to some criteria.</li>
- * </ul>
- * </p>
+ * The push method can be called directly, but will also be called automatically
+ * if a new <code>LogRecord</code> is added that has a level greater than or
+ * equal to than the value defined for the property
+ * java.util.logging.MemoryHandler.push.
* <p>
* {@code MemoryHandler} will read following {@code LogManager} properties for
* initialization, if given properties are not defined or has invalid values,
* default value will be used.
* <ul>
- * <li>java.util.logging.MemoryHandler.level specifies the level for this
- * {@code Handler}, defaults to {@code Level.ALL}.</li>
* <li>java.util.logging.MemoryHandler.filter specifies the {@code Filter}
* class name, defaults to no {@code Filter}.</li>
- * <li>java.util.logging.MemoryHandler.size specifies the buffer size in number
- * of {@code LogRecord}, defaults to 1000.</li>
+ * <li>java.util.logging.MemoryHandler.level specifies the level for this
+ * {@code Handler}, defaults to {@code Level.ALL}.</li>
* <li>java.util.logging.MemoryHandler.push specifies the push level, defaults
* to level.SEVERE.</li>
+ * <li>java.util.logging.MemoryHandler.size specifies the buffer size in number
+ * of {@code LogRecord}, defaults to 1000.</li>
* <li>java.util.logging.MemoryHandler.target specifies the class of the target
* {@code Handler}, no default value, which means this property must be
* specified either by property setting or by constructor.</li>
* </ul>
- * </p>
*/
public class MemoryHandler extends Handler {
- //default maximum buffered number of LogRecord
+ // default maximum buffered number of LogRecord
private static final int DEFAULT_SIZE = 1000;
- //target handler
+
+ // target handler
private Handler target;
-
- //buffer size
+
+ // buffer size
private int size = DEFAULT_SIZE;
-
- //push level
+
+ // push level
private Level push = Level.SEVERE;
- //LogManager instance for convenience
+ // LogManager instance for convenience
private final LogManager manager = LogManager.getLogManager();
-
- //buffer
+
+ // buffer
private LogRecord[] buffer;
-
- //current position in buffer
+
+ // current position in buffer
private int cursor;
-
+
/**
* Default constructor, construct and init a {@code MemoryHandler} using
* {@code LogManager} properties or default values.
- *
+ *
* @throws RuntimeException
* if property value are invalid and no default value could be
* used.
@@ -99,55 +91,57 @@
public MemoryHandler() {
super();
String className = this.getClass().getName();
- //init target
- final String targetName = manager.getProperty(className+".target"); //$NON-NLS-1$
+ // init target
+ final String targetName = manager.getProperty(className + ".target"); //$NON-NLS-1$
try {
- Class<?> targetClass = AccessController.doPrivileged(new PrivilegedExceptionAction<Class<?>>(){
- public Class<?> run() throws Exception{
- ClassLoader loader = Thread.currentThread().getContextClassLoader();
- if(loader == null){
- loader = ClassLoader.getSystemClassLoader();
- }
- return loader.loadClass(targetName);
- }
- });
+ Class<?> targetClass = AccessController
+ .doPrivileged(new PrivilegedExceptionAction<Class<?>>() {
+ public Class<?> run() throws Exception {
+ ClassLoader loader = Thread.currentThread()
+ .getContextClassLoader();
+ if (loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+ return loader.loadClass(targetName);
+ }
+ });
target = (Handler) targetClass.newInstance();
} catch (Exception e) {
// logging.10=Cannot load target handler:{0}
throw new RuntimeException(Messages.getString("logging.10", //$NON-NLS-1$
targetName));
}
- //init size
- String sizeString = manager.getProperty(className+".size"); //$NON-NLS-1$
+ // init size
+ String sizeString = manager.getProperty(className + ".size"); //$NON-NLS-1$
if (null != sizeString) {
try {
size = Integer.parseInt(sizeString);
- if(size <= 0){
+ if (size <= 0) {
size = DEFAULT_SIZE;
}
} catch (Exception e) {
- printInvalidPropMessage(className+".size", sizeString, e); //$NON-NLS-1$
+ printInvalidPropMessage(className + ".size", sizeString, e); //$NON-NLS-1$
}
}
- //init push level
- String pushName = manager.getProperty(className+".push"); //$NON-NLS-1$
+ // init push level
+ String pushName = manager.getProperty(className + ".push"); //$NON-NLS-1$
if (null != pushName) {
try {
push = Level.parse(pushName);
} catch (Exception e) {
- printInvalidPropMessage(className+".push", pushName, e); //$NON-NLS-1$
+ printInvalidPropMessage(className + ".push", pushName, e); //$NON-NLS-1$
}
}
- //init other properties which are common for all Handler
- initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
+ // init other properties which are common for all Handler
+ initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
buffer = new LogRecord[size];
}
-
+
/**
* Construct and init a {@code MemoryHandler} using given target, size and
* push level, other properties using {@code LogManager} properties or
* default values.
- *
+ *
* @param target
* the given {@code Handler} to output
* @param size
@@ -156,7 +150,7 @@
* @param pushLevel
* the push level
* @throws IllegalArgumentException
- * if {@code size}<=0
+ * if {@code size <= 0}
* @throws RuntimeException
* if property value are invalid and no default value could be
* used.
@@ -171,13 +165,13 @@
this.target = target;
this.size = size;
this.push = pushLevel;
- initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
+ initProperties("ALL", null, "java.util.logging.SimpleFormatter", null); //$NON-NLS-1$//$NON-NLS-2$
buffer = new LogRecord[size];
}
-
+
/**
* Close this handler and target handler, free all associated resources.
- *
+ *
* @throws SecurityException
* if security manager exists and it determines that caller does
* not have the required permissions to control this handler.
@@ -204,7 +198,7 @@
* Furthermore if the record's level is not less than the push level, the
* push action is triggered to output all the buffered records to the target
* handler, and the target handler will publish them.
- *
+ *
* @param record
* the log record
*/
@@ -225,7 +219,7 @@
/**
* Return the push level.
- *
+ *
* @return the push level
*/
public Level getPushLevel() {
@@ -233,18 +227,14 @@
}
/**
- * <p>
* Check if given {@code LogRecord} would be put into this
* {@code MemoryHandler}'s internal buffer.
- * </p>
* <p>
* The given {@code LogRecord} is loggable if and only if it has appropriate
* level and it pass any associated filter's check.
- * </p>
* <p>
* Note that the push level is not used for this check.
- * </p>
- *
+ *
* @param record
* the given {@code LogRecord}
* @return the given {@code LogRecord} if it should be logged, {@code false}
@@ -261,13 +251,13 @@
*/
public void push() {
for (int i = cursor; i < size; i++) {
- if(null != buffer[i]) {
+ if (null != buffer[i]) {
target.publish(buffer[i]);
}
buffer[i] = null;
}
for (int i = 0; i < cursor; i++) {
- if(null != buffer[i]) {
+ if (null != buffer[i]) {
target.publish(buffer[i]);
}
buffer[i] = null;
@@ -276,15 +266,15 @@
}
/**
- * Set the push level. The push level is used to check the push action
+ * Set the push level. The push level is used to check the push action
* triggering. When a new {@code LogRecord} is put into the internal
- * buffer and its level is not less than the push level, the push action
+ * buffer and its level is not less than the push level, the push action
* will be triggered. Note that set new push level won't trigger push action.
- *
+ *
* @param newLevel
* the new level to set.
* @throws SecurityException
- * if security manager exists and it determines that caller
+ * if security manager exists and it determines that caller
* does not have the required permissions to control this handler.
*/
public void setPushLevel(Level newLevel) {
diff --git a/libcore/logging/src/main/java/java/util/logging/SimpleFormatter.java b/libcore/logging/src/main/java/java/util/logging/SimpleFormatter.java
index 1595796..def4ad3 100644
--- a/libcore/logging/src/main/java/java/util/logging/SimpleFormatter.java
+++ b/libcore/logging/src/main/java/java/util/logging/SimpleFormatter.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.io.PrintWriter;
@@ -26,13 +25,10 @@
/**
* {@code SimpleFormatter} can be used to print a summary of the information
* contained in a {@code LogRecord} object in a human readable format.
- * @since Android 1.0
*/
public class SimpleFormatter extends Formatter {
/**
* Constructs a new {@code SimpleFormatter}.
- *
- * @since Android 1.0
*/
public SimpleFormatter() {
super();
@@ -41,11 +37,10 @@
/**
* Converts a {@link LogRecord} object into a human readable string
* representation.
- *
+ *
* @param r
* the log record to be formatted into a string.
* @return the formatted string.
- * @since Android 1.0
*/
@Override
public String format(LogRecord r) {
@@ -53,7 +48,8 @@
sb.append(MessageFormat.format("{0, date} {0, time} ", //$NON-NLS-1$
new Object[] { new Date(r.getMillis()) }));
sb.append(r.getSourceClassName()).append(" "); //$NON-NLS-1$
- sb.append(r.getSourceMethodName()).append(LogManager.getSystemLineSeparator()); //$NON-NLS-1$
+ sb.append(r.getSourceMethodName()).append(
+ LogManager.getSystemLineSeparator());
sb.append(r.getLevel().getName()).append(": "); //$NON-NLS-1$
sb.append(formatMessage(r)).append(LogManager.getSystemLineSeparator());
if (null != r.getThrown()) {
@@ -66,7 +62,7 @@
t.printStackTrace(pw);
sb.append(sw.toString());
} finally {
- if(pw != null){
+ if (pw != null) {
try {
pw.close();
} catch (Exception e) {
@@ -78,4 +74,3 @@
return sb.toString();
}
}
-
diff --git a/libcore/logging/src/main/java/java/util/logging/SocketHandler.java b/libcore/logging/src/main/java/java/util/logging/SocketHandler.java
index 8626007..38cfd64 100644
--- a/libcore/logging/src/main/java/java/util/logging/SocketHandler.java
+++ b/libcore/logging/src/main/java/java/util/logging/SocketHandler.java
@@ -15,12 +15,11 @@
* limitations under the License.
*/
-
package java.util.logging;
-import java.net.Socket;
import java.io.BufferedOutputStream;
import java.io.IOException;
+import java.net.Socket;
import org.apache.harmony.logging.internal.nls.Messages;
@@ -48,16 +47,14 @@
* <li>java.util.logging.SocketHandler.encoding specifies the port number that
* this handler should connect to. There's no default value for this property.
* </ul>
- * </p>
* <p>
* This handler buffers the outgoing messages, but flushes each time a log
* record has been published.
- * </p>
* <p>
* This class is not thread-safe.
- * </p>
*/
public class SocketHandler extends StreamHandler {
+
// default level
private static final String DEFAULT_LEVEL = "ALL"; //$NON-NLS-1$
@@ -71,7 +68,7 @@
* Constructs a {@code SocketHandler} object using the properties read by
* the log manager, including the host name and port number. Default
* formatting uses the XMLFormatter class and level is set to ALL.
- *
+ *
* @throws IOException
* if failed to connect to the specified host and port.
* @throws IllegalArgumentException
@@ -92,7 +89,7 @@
* Constructs a {@code SocketHandler} object using the specified host name
* and port number together with other properties read by the log manager.
* Default formatting uses the XMLFormatter class and level is set to ALL.
- *
+ *
* @param host
* the host name
* @param port
@@ -146,7 +143,7 @@
/**
* Closes this handler. The network connection to the host is also closed.
- *
+ *
* @throws SecurityException
* If a security manager determines that the caller does not
* have the required permission to control this handler.
@@ -168,7 +165,7 @@
/**
* Logs a record if necessary. A flush operation will be done afterwards.
- *
+ *
* @param record
* the log record to be logged.
*/
@@ -177,5 +174,4 @@
super.publish(record);
super.flush();
}
-
}
diff --git a/libcore/logging/src/main/java/java/util/logging/StreamHandler.java b/libcore/logging/src/main/java/java/util/logging/StreamHandler.java
index ee12190..7049d45 100644
--- a/libcore/logging/src/main/java/java/util/logging/StreamHandler.java
+++ b/libcore/logging/src/main/java/java/util/logging/StreamHandler.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.io.OutputStream;
@@ -30,30 +29,26 @@
* is, objects of the class {@link java.io.OutputStream}.
* <p>
* A {@code StreamHandler} object reads the following properties from the log
- * manager to initialize itself:
+ * manager to initialize itself. A default value will be used if a property is
+ * not found or has an invalid value.
* <ul>
- * <li>java.util.logging.StreamHandler.level specifies the logging level,
- * defaults to {@code Level.INFO} if this property is not found or has an
- * invalid value.
- * <li>java.util.logging.StreamHandler.filter specifies the name of the filter
- * class to be associated with this handler, defaults to {@code null} if this
- * property is not found or has an invalid value.
- * <li>java.util.logging.StreamHandler.formatter specifies the name of the
- * formatter class to be associated with this handler, defaults to
- * {@code java.util.logging.SimpleFormatter} if this property is not found or
- * has an invalid value.
* <li>java.util.logging.StreamHandler.encoding specifies the encoding this
- * handler will use to encode log messages, defaults to {@code null} if this
- * property is not found or has an invalid value.
+ * handler will use to encode log messages. Default is the encoding used by the
+ * current platform.
+ * <li>java.util.logging.StreamHandler.filter specifies the name of the filter
+ * class to be associated with this handler. No <code>Filter</code> is used by
+ * default.
+ * <li>java.util.logging.StreamHandler.formatter specifies the name of the
+ * formatter class to be associated with this handler. Default is
+ * {@code java.util.logging.SimpleFormatter}.
+ * <li>java.util.logging.StreamHandler.level specifies the logging level.
+ * Defaults is {@code Level.INFO}.
* </ul>
- * </p>
* <p>
* This class is not thread-safe.
- * </p>
- *
- * @since Android 1.0
*/
public class StreamHandler extends Handler {
+
// the output stream this handler writes to
private OutputStream os;
@@ -66,11 +61,9 @@
/**
* Constructs a {@code StreamHandler} object. The new stream handler
* does not have an associated output stream.
- *
- * @since Android 1.0
*/
public StreamHandler() {
- initProperties("INFO", null, "java.util.logging.SimpleFormatter", //$NON-NLS-1$//$NON-NLS-2$
+ initProperties("INFO", null, "java.util.logging.SimpleFormatter", //$NON-NLS-1$//$NON-NLS-2$
null);
this.os = null;
this.writer = null;
@@ -80,7 +73,7 @@
/**
* Constructs a {@code StreamHandler} object with the supplied output
* stream. Default properties are read.
- *
+ *
* @param os
* the output stream this handler writes to.
*/
@@ -106,14 +99,13 @@
/**
* Constructs a {@code StreamHandler} object with the supplied output stream
* and formatter.
- *
+ *
* @param os
* the output stream this handler writes to.
* @param formatter
* the formatter this handler uses to format the output.
* @throws NullPointerException
* if {@code os} or {@code formatter} is {@code null}.
- * @since Android 1.0
*/
public StreamHandler(OutputStream os, Formatter formatter) {
this();
@@ -160,7 +152,7 @@
/**
* Sets the output stream this handler writes to. Note it does nothing else.
- *
+ *
* @param newOs
* the new output stream
*/
@@ -168,13 +160,12 @@
this.os = newOs;
}
-
/**
* Sets the output stream this handler writes to. If there's an existing
* output stream, the tail string of the associated formatter will be
- * written to it. Then it will be flushed, closed and replaced with
+ * written to it. Then it will be flushed, closed and replaced with
* {@code os}.
- *
+ *
* @param os
* the new output stream.
* @throws SecurityException
@@ -197,7 +188,7 @@
/**
* Sets the character encoding used by this handler. A {@code null} value
* indicates that the default encoding should be used.
- *
+ *
* @param encoding
* the character encoding to set.
* @throws SecurityException
@@ -205,12 +196,11 @@
* have the required permission.
* @throws UnsupportedEncodingException
* if the specified encoding is not supported by the runtime.
- * @since Android 1.0
*/
@Override
public void setEncoding(String encoding) throws SecurityException,
UnsupportedEncodingException {
- //flush first before set new encoding
+ // flush first before set new encoding
this.flush();
super.setEncoding(encoding);
// renew writer only if the writer exists
@@ -234,7 +224,7 @@
/**
* Closes this handler, but the underlying output stream is only closed if
* {@code closeStream} is {@code true}. Security is not checked.
- *
+ *
* @param closeStream
* whether to close the underlying output stream.
*/
@@ -264,11 +254,10 @@
* this handler is written out. A flush operation and a subsequent close
* operation is then performed upon the output stream. Client applications
* should not use a handler after closing it.
- *
+ *
* @throws SecurityException
* if a security manager determines that the caller does not
* have the required permission.
- * @since Android 1.0
*/
@Override
public void close() {
@@ -278,8 +267,6 @@
/**
* Flushes any buffered output.
- *
- * @since Android 1.0
*/
@Override
public void flush() {
@@ -291,7 +278,8 @@
this.os.flush();
}
} catch (Exception e) {
- // logging.16=Exception occurred while flushing the output stream.
+ // logging.16=Exception occurred while flushing the output
+ // stream.
getErrorManager().error(Messages.getString("logging.16"), //$NON-NLS-1$
e, ErrorManager.FLUSH_FAILURE);
}
@@ -309,10 +297,9 @@
* </ul>
* If it is the first time a log record is written out, the head string of
* the formatter associated with this handler is written out first.
- *
+ *
* @param record
* the log record to be logged.
- * @since Android 1.0
*/
@Override
public synchronized void publish(LogRecord record) {
@@ -325,7 +312,8 @@
try {
msg = getFormatter().format(record);
} catch (Exception e) {
- // logging.17=Exception occurred while formatting the log record.
+ // logging.17=Exception occurred while formatting the log
+ // record.
getErrorManager().error(Messages.getString("logging.17"), //$NON-NLS-1$
e, ErrorManager.FORMAT_FAILURE);
}
@@ -345,13 +333,11 @@
* {@code false}.
* <p>
* Notice : Case of no output stream will return {@code false}.
- * </p>
- *
+ *
* @param record
* the log record to be checked.
* @return {@code true} if {@code record} needs to be logged, {@code false}
* otherwise.
- * @since Android 1.0
*/
@Override
public boolean isLoggable(LogRecord record) {
@@ -363,5 +349,4 @@
}
return false;
}
-
}
diff --git a/libcore/logging/src/main/java/java/util/logging/XMLFormatter.java b/libcore/logging/src/main/java/java/util/logging/XMLFormatter.java
index 6279d8c..ff96813 100644
--- a/libcore/logging/src/main/java/java/util/logging/XMLFormatter.java
+++ b/libcore/logging/src/main/java/java/util/logging/XMLFormatter.java
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-
package java.util.logging;
import java.security.AccessController;
@@ -30,8 +29,6 @@
* {@code XMLFormatter} uses the output handler's encoding if it is specified,
* otherwise the default platform encoding is used instead. UTF-8 is the
* recommended encoding.
- *
- * @since Android 1.0
*/
public class XMLFormatter extends Formatter {
@@ -42,8 +39,6 @@
/**
* Constructs a new {@code XMLFormatter}.
- *
- * @since Android 1.0
*/
public XMLFormatter() {
super();
@@ -51,61 +46,63 @@
/**
* Converts a {@code LogRecord} into an XML string.
- *
+ *
* @param r
* the log record to be formatted.
* @return the log record formatted as an XML string.
- * @since Android 1.0
*/
+ @SuppressWarnings("nls")
@Override
public String format(LogRecord r) {
- //call a method of LogRecord to ensure not null
+ // call a method of LogRecord to ensure not null
long time = r.getMillis();
- //format to date
- String date = MessageFormat.format("{0, date} {0, time}", //$NON-NLS-1$
+ // format to date
+ String date = MessageFormat.format("{0, date} {0, time}",
new Object[] { new Date(time) });
StringBuilder sb = new StringBuilder();
- sb.append(("<record>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<date>")).append(date).append(("</date>")) //$NON-NLS-1$ //$NON-NLS-2$
+ sb.append(("<record>")).append(lineSeperator);
+ sb.append(indent).append(("<date>")).append(date).append(("</date>"))
.append(lineSeperator);
- sb.append(indent).append(("<millis>")).append(time).append( //$NON-NLS-1$
- ("</millis>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<sequence>")).append(r.getSequenceNumber()) //$NON-NLS-1$
- .append(("</sequence>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<millis>")).append(time).append(
+ ("</millis>")).append(lineSeperator);
+ sb.append(indent).append(("<sequence>")).append(r.getSequenceNumber())
+ .append(("</sequence>")).append(lineSeperator);
if (null != r.getLoggerName()) {
- sb.append(indent).append(("<logger>")).append(r.getLoggerName()) //$NON-NLS-1$
- .append(("</logger>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<logger>")).append(r.getLoggerName())
+ .append(("</logger>")).append(lineSeperator);
}
- sb.append(indent).append(("<level>")).append(r.getLevel().getName()) //$NON-NLS-1$
- .append(("</level>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<level>")).append(r.getLevel().getName())
+ .append(("</level>")).append(lineSeperator);
if (null != r.getSourceClassName()) {
- sb.append(indent).append(("<class>")) //$NON-NLS-1$
- .append(r.getSourceClassName()).append(("</class>")) //$NON-NLS-1$
+ sb.append(indent).append(("<class>"))
+ .append(r.getSourceClassName()).append(("</class>"))
.append(lineSeperator);
}
if (null != r.getSourceMethodName()) {
- sb.append(indent).append(("<method>")).append( //$NON-NLS-1$
- r.getSourceMethodName()).append(("</method>")).append( //$NON-NLS-1$
+ sb.append(indent).append(("<method>")).append(
+ r.getSourceMethodName()).append(("</method>")).append(
lineSeperator);
}
- sb.append(indent).append(("<thread>")).append(r.getThreadID()).append( //$NON-NLS-1$
- ("</thread>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<thread>")).append(r.getThreadID()).append(
+ ("</thread>")).append(lineSeperator);
formatMessages(r, sb);
Object[] params;
if ((params = r.getParameters()) != null) {
for (Object element : params) {
- sb.append(indent).append(("<param>")).append(element).append( //$NON-NLS-1$
- ("</param>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<param>")).append(element).append(
+ ("</param>")).append(lineSeperator);
}
}
formatThrowable(r, sb);
- sb.append(("</record>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(("</record>")).append(lineSeperator);
return sb.toString();
}
+ @SuppressWarnings("nls")
private void formatMessages(LogRecord r, StringBuilder sb) {
- //get localized message if has, but don't call Formatter.formatMessage to parse pattern string
+ // get localized message if has, but don't call Formatter.formatMessage
+ // to parse pattern string
ResourceBundle rb = r.getResourceBundle();
String pattern = r.getMessage();
if (null != rb && null != pattern) {
@@ -118,49 +115,50 @@
if (message == null) {
message = pattern;
- sb.append(indent).append(("<message>")).append(message).append( //$NON-NLS-1$
- ("</message>")).append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append(("<message>")).append(message).append(
+ ("</message>")).append(lineSeperator);
} else {
- sb.append(indent).append(("<message>")).append(message).append( //$NON-NLS-1$
- ("</message>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<key>")).append(pattern).append( //$NON-NLS-1$
- ("</key>")).append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(("<catalog>")).append( //$NON-NLS-1$
- r.getResourceBundleName()).append(("</catalog>")) //$NON-NLS-1$
+ sb.append(indent).append(("<message>")).append(message).append(
+ ("</message>")).append(lineSeperator);
+ sb.append(indent).append(("<key>")).append(pattern).append(
+ ("</key>")).append(lineSeperator);
+ sb.append(indent).append(("<catalog>")).append(
+ r.getResourceBundleName()).append(("</catalog>"))
.append(lineSeperator);
}
- } else if(null != pattern){
- sb.append(indent).append(("<message>")).append(pattern).append( //$NON-NLS-1$
- ("</message>")).append(lineSeperator); //$NON-NLS-1$
- } else{
- sb.append(indent).append(("<message/>")); //$NON-NLS-1$
+ } else if (null != pattern) {
+ sb.append(indent).append(("<message>")).append(pattern).append(
+ ("</message>")).append(lineSeperator);
+ } else {
+ sb.append(indent).append(("<message/>"));
}
}
+ @SuppressWarnings("nls")
private void formatThrowable(LogRecord r, StringBuilder sb) {
Throwable t;
if ((t = r.getThrown()) != null) {
- sb.append(indent).append("<exception>").append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(indent).append("<message>").append( //$NON-NLS-1$
- t.toString()).append("</message>").append(lineSeperator); //$NON-NLS-1$
- //format throwable's stack trace
+ sb.append(indent).append("<exception>").append(lineSeperator);
+ sb.append(indent).append(indent).append("<message>").append(
+ t.toString()).append("</message>").append(lineSeperator);
+ // format throwable's stack trace
StackTraceElement[] elements = t.getStackTrace();
for (StackTraceElement e : elements) {
- sb.append(indent).append(indent).append("<frame>").append( //$NON-NLS-1$
+ sb.append(indent).append(indent).append("<frame>").append(
lineSeperator);
sb.append(indent).append(indent).append(indent).append(
- "<class>").append(e.getClassName()).append("</class>") //$NON-NLS-1$//$NON-NLS-2$
+ "<class>").append(e.getClassName()).append("</class>")
.append(lineSeperator);
sb.append(indent).append(indent).append(indent).append(
- "<method>").append(e.getMethodName()).append( //$NON-NLS-1$
- "</method>").append(lineSeperator); //$NON-NLS-1$
+ "<method>").append(e.getMethodName()).append(
+ "</method>").append(lineSeperator);
sb.append(indent).append(indent).append(indent)
- .append("<line>").append(e.getLineNumber()).append( //$NON-NLS-1$
- "</line>").append(lineSeperator); //$NON-NLS-1$
- sb.append(indent).append(indent).append("</frame>").append( //$NON-NLS-1$
+ .append("<line>").append(e.getLineNumber()).append(
+ "</line>").append(lineSeperator);
+ sb.append(indent).append(indent).append("</frame>").append(
lineSeperator);
}
- sb.append(indent).append("</exception>").append(lineSeperator); //$NON-NLS-1$
+ sb.append(indent).append("</exception>").append(lineSeperator);
}
}
@@ -168,54 +166,48 @@
* Returns the header string for a set of log records formatted as XML
* strings, using the output handler's encoding if it is defined, otherwise
* using the default platform encoding.
- *
+ *
* @param h
* the output handler, may be {@code null}.
* @return the header string for log records formatted as XML strings.
- * @since Android 1.0
*/
+ @SuppressWarnings("nls")
@Override
public String getHead(Handler h) {
String encoding = null;
- if(null != h) {
+ if (null != h) {
encoding = h.getEncoding();
}
if (null == encoding) {
- encoding = getSystemProperty("file.encoding"); //$NON-NLS-1$
+ encoding = getSystemProperty("file.encoding");
}
StringBuilder sb = new StringBuilder();
- sb.append("<?xml version=\"1.0\" encoding=\"").append(encoding).append( //$NON-NLS-1$
- "\" standalone=\"no\"?>").append(lineSeperator); //$NON-NLS-1$
- sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">").append(lineSeperator); //$NON-NLS-1$
- sb.append(("<log>")); //$NON-NLS-1$
+ sb.append("<?xml version=\"1.0\" encoding=\"").append(encoding).append(
+ "\" standalone=\"no\"?>").append(lineSeperator);
+ sb.append("<!DOCTYPE log SYSTEM \"logger.dtd\">").append(lineSeperator);
+ sb.append(("<log>"));
return sb.toString();
}
/**
* Returns the tail string for a set of log records formatted as XML
* strings.
- *
+ *
* @param h
* the output handler, may be {@code null}.
* @return the tail string for log records formatted as XML strings.
- * @since Android 1.0
*/
@Override
- @SuppressWarnings("unused")
public String getTail(Handler h) {
return "</log>"; //$NON-NLS-1$
}
- //use privilege code to get system property
+ // use privilege code to get system property
private static String getSystemProperty(final String key) {
- return AccessController.doPrivileged(
- new PrivilegedAction<String>() {
+ return AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(key);
}
});
}
-
}
-
-
diff --git a/libcore/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java b/libcore/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java
index 3a06078..f2bd62d 100644
--- a/libcore/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java
+++ b/libcore/logging/src/test/java/org/apache/harmony/logging/tests/java/util/logging/LoggerTest.java
@@ -29,6 +29,8 @@
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.LoggingPermission;
+import java.io.File;
+import java.io.FileInputStream;
import junit.framework.TestCase;
@@ -4628,6 +4630,26 @@
}
}
+ /*
+ * test initHandler
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "initHandler",
+ args = {}
+ )
+ public void test_initHandler() throws Exception {
+ File logProps = new File(LOGGING_CONFIG_FILE);
+ LogManager lm = LogManager.getLogManager();
+ lm.readConfiguration(new FileInputStream(logProps));
+
+ Logger log = Logger.getLogger("");
+ // can log properly
+ Handler[] handlers = log.getHandlers();
+ assertEquals(2, handlers.length);
+ }
+
/*
* A mock logger, used to test the protected constructors and fields.
diff --git a/libcore/logging/src/test/resources/config/java/util/logging/logging.config b/libcore/logging/src/test/resources/config/java/util/logging/logging.config
index f4c5146..6e7394b 100644
--- a/libcore/logging/src/test/resources/config/java/util/logging/logging.config
+++ b/libcore/logging/src/test/resources/config/java/util/logging/logging.config
@@ -1,3 +1,3 @@
-handlers=org.apache.harmony.logging.tests.java.util.logging.LogManagerTest$MockHandler java.util.logging.ConsoleHandler
+handlers=org.apache.harmony.logging.tests.java.util.logging.LogManagerTest$MockHandler , java.util.logging.ConsoleHandler
.level=ALL
org.apache.harmony.logging.tests.java.util.logging.LogManagerTest$MockHandler.level=OFF
\ No newline at end of file
diff --git a/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.c b/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.c
index fcff1df..eaefc9f 100644
--- a/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.c
+++ b/libcore/luni-kernel/src/main/native/java_lang_ProcessManager.c
@@ -91,7 +91,8 @@
while (1) {
int status;
- pid_t pid = wait(&status);
+ /* wait for children in our process group */
+ pid_t pid = waitpid(0, &status, 0);
if (pid >= 0) {
// Extract real status.
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java b/libcore/luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java
new file mode 100644
index 0000000..d7c2ab8
--- /dev/null
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/util/InputStreamExposer.java
@@ -0,0 +1,117 @@
+/*
+ * 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.luni.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * The class contains static {@link java.io.InputStream} utilities.
+ */
+public class InputStreamExposer {
+
+ /**
+ * Provides access to a protected underlying buffer of
+ * <code>ByteArrayInputStream</code>.
+ */
+ private static final Field BAIS_BUF;
+
+ /**
+ * Provides access to a protected position in the underlying buffer of
+ * <code>ByteArrayInputStream</code>.
+ */
+ private static final Field BAIS_POS;
+
+ static {
+ final Field[] f = new Field[2];
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ public Object run() {
+ try {
+ f[0] = ByteArrayInputStream.class.getDeclaredField("buf");
+ f[0].setAccessible(true);
+ f[1] = ByteArrayInputStream.class.getDeclaredField("pos");
+ f[1].setAccessible(true);
+ } catch (NoSuchFieldException nsfe) {
+ throw new InternalError(nsfe.getLocalizedMessage());
+ }
+ return null;
+ }
+ });
+ BAIS_BUF = f[0];
+ BAIS_POS = f[1];
+ }
+
+ /**
+ * Reads all bytes from {@link java.io.ByteArrayInputStream} using its
+ * underlying buffer directly.
+ *
+ * @return an underlying buffer, if a current position is at the buffer
+ * beginning, and an end position is at the buffer end, or a copy of
+ * the underlying buffer part.
+ */
+ private static byte[] expose(ByteArrayInputStream bais) {
+ byte[] buffer, buf;
+ int pos;
+ synchronized (bais) {
+ int available = bais.available();
+ try {
+ buf = (byte[]) BAIS_BUF.get(bais);
+ pos = BAIS_POS.getInt(bais);
+ } catch (IllegalAccessException iae) {
+ throw new InternalError(iae.getLocalizedMessage());
+ }
+ if (pos == 0 && available == buf.length) {
+ buffer = buf;
+ } else {
+ buffer = new byte[available];
+ System.arraycopy(buf, pos, buffer, 0, available);
+ }
+ bais.skip(available);
+ }
+ return buffer;
+ }
+
+ /**
+ * The utility method for reading the whole input stream into a snapshot
+ * buffer. To speed up the access it works with an underlying buffer for a
+ * given {@link java.io.ByteArrayInputStream}.
+ *
+ * @param is
+ * the stream to be read.
+ * @return the snapshot wrapping the buffer where the bytes are read to.
+ * @throws UnsupportedOperationException if the input stream data cannot be exposed
+ */
+ public static byte[] expose(InputStream is) throws IOException, UnsupportedOperationException {
+ // BEGIN android-changed
+ // if (is instanceof ExposedByteArrayInputStream) {
+ // return ((ExposedByteArrayInputStream) is).expose();
+ // }
+
+ if (is.getClass().equals(ByteArrayInputStream.class)) {
+ return expose((ByteArrayInputStream) is);
+ }
+
+ // We don't know how to do this
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/libcore/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java b/libcore/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java
new file mode 100644
index 0000000..cdfe0c8
--- /dev/null
+++ b/libcore/luni/src/main/java/org/apache/harmony/luni/util/ThreadLocalCache.java
@@ -0,0 +1,103 @@
+/*
+ * 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.luni.util;
+
+import java.lang.ref.SoftReference;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+
+/**
+ * The class extends the functionality of {@link java.lang.ThreadLocal} with
+ * possibility of discarding the thread local storage content when a heap is
+ * exhausted.
+ */
+public class ThreadLocalCache<T> {
+
+ private SoftReference<ThreadLocal<T>> storage = new SoftReference<ThreadLocal<T>>(
+ null);
+
+ private ThreadLocal<T> getThreadLocal() {
+ ThreadLocal<T> tls = storage.get();
+ if (tls == null) {
+ tls = new ThreadLocal<T>() {
+ public T initialValue() {
+ return ThreadLocalCache.this.initialValue();
+ }
+ };
+ storage = new SoftReference<ThreadLocal<T>>(tls);
+ }
+ return tls;
+ }
+
+ /**
+ * Returns the initial value for the cache for the current thread.
+ */
+ protected T initialValue() {
+ return null;
+ }
+
+ /**
+ * Returns the thread local value of this object.
+ */
+ public T get() {
+ return getThreadLocal().get();
+ }
+
+ /**
+ * Sets the value of this variable for the current thread. Might be useful
+ * for expanding the thread local cache.
+ */
+ public void set(T value) {
+ getThreadLocal().set(value);
+ }
+
+ /**
+ * Discards the cache for all threads.
+ */
+ public void remove() {
+ storage.clear();
+ }
+
+ public static ThreadLocalCache<CharsetDecoder> utf8Decoder = new ThreadLocalCache<CharsetDecoder>() {
+ protected CharsetDecoder initialValue() {
+ return Charset.forName("UTF-8").newDecoder();
+ }
+ };
+
+ public static ThreadLocalCache<CharsetEncoder> utf8Encoder = new ThreadLocalCache<CharsetEncoder>() {
+ protected CharsetEncoder initialValue() {
+ return Charset.forName("UTF-8").newEncoder();
+ }
+ };
+
+ public static ThreadLocalCache<java.nio.ByteBuffer> byteBuffer = new ThreadLocalCache<java.nio.ByteBuffer>() {
+ protected java.nio.ByteBuffer initialValue() {
+ return java.nio.ByteBuffer.allocate(72); // >=
+ // Manifest.LINE_LENGTH_LIMIT
+ }
+ };
+
+ public static ThreadLocalCache<CharBuffer> charBuffer = new ThreadLocalCache<CharBuffer>() {
+ protected CharBuffer initialValue() {
+ return CharBuffer.allocate(72); // no specific requirement
+ }
+ };
+
+}
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
index 5bd7907..3f7b0b1 100644
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp
@@ -14,14 +14,26 @@
* limitations under the License.
*/
+#define LOG_TAG "OSMemory"
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
#include "utils/misc.h"
+#include "utils/Log.h"
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+/*
+ * Cached dalvik.system.VMRuntime pieces.
+ */
+static struct {
+ jmethodID method_trackExternalAllocation;
+ jmethodID method_trackExternalFree;
+
+ jobject runtimeInstance;
+} gIDCache;
+
#undef MMAP_READ_ONLY
#define MMAP_READ_ONLY 1L
#undef MMAP_READ_WRITE
@@ -55,11 +67,28 @@
* Signature: (I)I
*/
static jint harmony_nio_mallocImpl(JNIEnv *_env, jobject _this, jint size) {
- void *returnValue = malloc(size);
- if(returnValue == NULL) {
- jniThrowException(_env, "java.lang.OutOfMemoryError", "");
+ jboolean allowed = _env->CallBooleanMethod(gIDCache.runtimeInstance,
+ gIDCache.method_trackExternalAllocation, (jlong) size);
+ if (!allowed) {
+ LOGW("External allocation of %d bytes was rejected\n", size);
+ jniThrowException(_env, "java/lang/OutOfMemoryError", NULL);
+ return 0;
}
- return (jint)returnValue;
+
+ LOGV("OSMemory alloc %d\n", size);
+ void *returnValue = malloc(size + sizeof(jlong));
+ if (returnValue == NULL) {
+ jniThrowException(_env, "java/lang/OutOfMemoryError", NULL);
+ return 0;
+ }
+
+ /*
+ * Tuck a copy of the size at the head of the buffer. We need this
+ * so harmony_nio_freeImpl() knows how much memory is being freed.
+ */
+ jlong* adjptr = (jlong*) returnValue;
+ *adjptr++ = size;
+ return (jint)adjptr;
}
/*
@@ -68,7 +97,12 @@
* Signature: (I)V
*/
static void harmony_nio_freeImpl(JNIEnv *_env, jobject _this, jint pointer) {
- free((void *)pointer);
+ jlong* adjptr = (jlong*) pointer;
+ jint size = *--adjptr;
+ LOGV("OSMemory free %d\n", size);
+ _env->CallVoidMethod(gIDCache.runtimeInstance,
+ gIDCache.method_trackExternalFree, (jlong) size);
+ free((void *)adjptr);
}
/*
@@ -577,6 +611,46 @@
{ "flushImpl", "(IJ)I", (void*) harmony_nio_flushImpl }
};
int register_org_apache_harmony_luni_platform_OSMemory(JNIEnv *_env) {
- return jniRegisterNativeMethods(_env, "org/apache/harmony/luni/platform/OSMemory",
+ /*
+ * We need to call VMRuntime.trackExternal{Allocation,Free}. Cache
+ * method IDs and a reference to the singleton.
+ */
+ static const char* kVMRuntimeName = "dalvik/system/VMRuntime";
+ jmethodID method_getRuntime;
+ jclass clazz;
+
+ clazz = _env->FindClass(kVMRuntimeName);
+ if (clazz == NULL) {
+ LOGE("Unable to find class %s\n", kVMRuntimeName);
+ return -1;
+ }
+ gIDCache.method_trackExternalAllocation = _env->GetMethodID(clazz,
+ "trackExternalAllocation", "(J)Z");
+ gIDCache.method_trackExternalFree = _env->GetMethodID(clazz,
+ "trackExternalFree", "(J)V");
+ method_getRuntime = _env->GetStaticMethodID(clazz,
+ "getRuntime", "()Ldalvik/system/VMRuntime;");
+
+ if (gIDCache.method_trackExternalAllocation == NULL ||
+ gIDCache.method_trackExternalFree == NULL ||
+ method_getRuntime == NULL)
+ {
+ LOGE("Unable to find VMRuntime methods\n");
+ return -1;
+ }
+
+ jobject instance = _env->CallStaticObjectMethod(clazz, method_getRuntime);
+ if (instance == NULL) {
+ LOGE("Unable to obtain VMRuntime instance\n");
+ return -1;
+ }
+ gIDCache.runtimeInstance = _env->NewGlobalRef(instance);
+
+ /*
+ * Register methods.
+ */
+ return jniRegisterNativeMethods(_env,
+ "org/apache/harmony/luni/platform/OSMemory",
gMethods, NELEM(gMethods));
}
+
diff --git a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
old mode 100755
new mode 100644
index f79c019..e105f5c
--- a/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
+++ b/libcore/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp
@@ -33,9 +33,13 @@
#include <cutils/properties.h>
#include <cutils/adb_networking.h>
-#include <utils/LogSocket.h>
#include "AndroidSystemNatives.h"
+// Temporary hack to build on systems that don't have up-to-date libc headers.
+#ifndef IPV6_TCLASS
+#define IPV6_TCLASS 67
+#endif
+
/**
* @name Socket Errors
* Error codes for socket operations
@@ -145,6 +149,9 @@
// wait for 500000 usec = 0.5 second
#define SEND_RETRY_TIME 500000
+// Local constants for getOrSetSocketOption
+#define SOCKOPT_GET 1
+#define SOCKOPT_SET 2
struct CachedFields {
jfieldID fd_descriptor;
@@ -238,30 +245,59 @@
}
/**
- * Converts a native address structure to a 4-byte array. Throws a
+ * Converts a native address structure to a Java byte array. Throws a
* NullPointerException or an IOException in case of error. This is
* signaled by a return value of -1. The normal return value is 0.
+ *
+ * @param address the sockaddr_storage structure to convert
+ *
+ * @exception SocketException the address family is unknown, or out of memory
+ *
*/
-static int structInToJavaAddress(
- JNIEnv *env, struct in_addr *address, jbyteArray java_address) {
+static jbyteArray socketAddressToAddressBytes(JNIEnv *env,
+ struct sockaddr_storage *address) {
- if (java_address == NULL) {
- return -1;
+ void *rawAddress;
+ size_t addressLength;
+ if (address->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) address;
+ rawAddress = &sin->sin_addr.s_addr;
+ addressLength = 4;
+ } else if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
+ rawAddress = &sin6->sin6_addr.s6_addr;
+ addressLength = 16;
+ } else {
+ throwSocketException(env, SOCKERR_BADAF);
+ return NULL;
}
- if (env->GetArrayLength(java_address) != sizeof(address->s_addr)) {
- return -1;
+ jbyteArray byteArray = env->NewByteArray(addressLength);
+ if (byteArray == NULL) {
+ throwSocketException(env, SOCKERR_NOBUFFERS);
+ return NULL;
}
+ env->SetByteArrayRegion(byteArray, 0, addressLength, (jbyte *) rawAddress);
- jbyte *java_address_bytes;
+ return byteArray;
+}
- java_address_bytes = env->GetByteArrayElements(java_address, NULL);
-
- memcpy(java_address_bytes, &(address->s_addr), sizeof(address->s_addr));
-
- env->ReleaseByteArrayElements(java_address, java_address_bytes, 0);
-
- return 0;
+/**
+ * Returns the port number in a sockaddr_storage structure.
+ *
+ * @param address the sockaddr_storage structure to get the port from
+ *
+ * @return the port number, or -1 if the address family is unknown.
+ */
+static int getSocketAddressPort(struct sockaddr_storage *address) {
+ switch (address->ss_family) {
+ case AF_INET:
+ return ntohs(((struct sockaddr_in *) address)->sin_port);
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6 *) address)->sin6_port);
+ default:
+ return -1;
+ }
}
/**
@@ -269,68 +305,79 @@
* Throws a NullPointerException or an IOException in case of
* error. This is signaled by a return value of -1. The normal
* return value is 0.
+ *
+ * @param sockaddress the sockaddr_storage structure to convert
+ *
+ * @return a jobject representing an InetAddress
*/
-static int socketAddressToInetAddress(JNIEnv *env,
- struct sockaddr_in *sockaddress, jobject inetaddress, int *port) {
+static jobject socketAddressToInetAddress(JNIEnv *env,
+ struct sockaddr_storage *sockaddress) {
- jbyteArray ipaddress;
- int result;
+ jbyteArray byteArray = socketAddressToAddressBytes(env, sockaddress);
+ if (byteArray == NULL) // Exception has already been thrown.
+ return NULL;
- ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
- gCachedFields.iaddr_ipaddress);
-
- if (structInToJavaAddress(env, &sockaddress->sin_addr, ipaddress) < 0) {
- return -1;
- }
-
- *port = ntohs(sockaddress->sin_port);
-
- return 0;
+ return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
+ gCachedFields.iaddr_getbyaddress, byteArray);
}
/**
- * Converts an InetAddress object to a native address structure.
- * Throws a NullPointerException or an IOException in case of
+ * Converts an InetAddress object and port number to a native address structure.
+ * Throws a NullPointerException or a SocketException in case of
* error. This is signaled by a return value of -1. The normal
* return value is 0.
+ *
+ * @param inetaddress the InetAddress object to convert
+ * @param port the port number
+ * @param sockaddress the sockaddr_storage structure to write to
+ *
+ * @return 0 on success, -1 on failure
+ *
+ * @exception SocketError if the address family is unknown
*/
static int inetAddressToSocketAddress(JNIEnv *env,
- jobject inetaddress, int port, struct sockaddr_in *sockaddress) {
+ jobject inetaddress, int port, struct sockaddr_storage *sockaddress) {
- jbyteArray ipaddress;
- int result;
-
- ipaddress = (jbyteArray)env->GetObjectField(inetaddress,
+ // Get the byte array that stores the IP address bytes in the InetAddress.
+ jbyteArray addressByteArray;
+ addressByteArray = (jbyteArray)env->GetObjectField(inetaddress,
gCachedFields.iaddr_ipaddress);
-
- memset(sockaddress, 0, sizeof(sockaddress));
-
- sockaddress->sin_family = AF_INET;
- sockaddress->sin_port = htons(port);
-
- if (javaAddressToStructIn(env, ipaddress, &(sockaddress->sin_addr)) < 0) {
- return -1;
+ if (addressByteArray == NULL) {
+ throwNullPointerException(env);
+ return -1;
}
- return 0;
-}
-
-static jobject structInToInetAddress(JNIEnv *env, struct in_addr *address) {
- jbyteArray bytes;
- int success;
-
- bytes = env->NewByteArray(4);
-
- if (bytes == NULL) {
- return NULL;
+ // Get the raw IP address bytes.
+ jbyte *addressBytes = env->GetByteArrayElements(addressByteArray, NULL);
+ if (addressBytes == NULL) {
+ throwNullPointerException(env);
+ return -1;
}
- if (structInToJavaAddress(env, address, bytes) < 0) {
- return NULL;
+ // Convert the IP address bytes to the proper IP address type.
+ size_t addressLength = env->GetArrayLength(addressByteArray);
+ int result = 0;
+ if (addressLength == 4) {
+ // IPv4 address.
+ struct sockaddr_in *sin = (struct sockaddr_in *) sockaddress;
+ memset(sin, 0, sizeof(struct sockaddr_in));
+ sin->sin_family = AF_INET;
+ sin->sin_port = htons(port);
+ memcpy(&sin->sin_addr.s_addr, addressBytes, 4);
+ } else if (addressLength == 16) {
+ // IPv6 address.
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sockaddress;
+ memset(sin6, 0, sizeof(struct sockaddr_in6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = htons(port);
+ memcpy(&sin6->sin6_addr.s6_addr, addressBytes, 16);
+ } else {
+ // Unknown address family.
+ throwSocketException(env, SOCKERR_BADAF);
+ result = -1;
}
-
- return env->CallStaticObjectMethod(gCachedFields.iaddr_class,
- gCachedFields.iaddr_getbyaddress, bytes);
+ env->ReleaseByteArrayElements(addressByteArray, addressBytes, 0);
+ return result;
}
/**
@@ -427,15 +474,77 @@
}
/**
- * check if the passed sockaddr_in struct contains a localhost address
+ * Check if the passed sockaddr_storage struct contains a localhost address
*
- * @param[in] address pointer to the address to check
+ * @param address address pointer to the address to check
*
* @return 0 if the passed address isn't a localhost address
*/
-static int isLocalhost(struct sockaddr_in *address) {
- // return address == 127.0.0.1
- return (unsigned int) address->sin_addr.s_addr == 16777343;
+static int isLocalHost(struct sockaddr_storage *address) {
+ if (address->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) address;
+ return (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK));
+ } else if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
+ return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
+ } else {
+ return 0;
+ }
+}
+
+/**
+ * Decide whether to use ADB networking for the given socket address.
+ *
+ * @param address pointer to sockaddr_storage structure to check
+ *
+ * @return true if ADB networking should be used, false otherwise.
+ */
+static bool useAdbNetworkingForAddress(struct sockaddr_storage *address) {
+ return useAdbNetworking && !isLocalHost(address) &&
+ address->ss_family == AF_INET;
+}
+
+/**
+ * Convert a sockaddr_storage structure to a string for logging purposes.
+ *
+ * @param address pointer to sockaddr_storage structure to print
+ *
+ * @return a string with the textual representation of the address.
+ *
+ * @note Returns a statically allocated buffer, so is not thread-safe.
+ */
+static char *socketAddressToString(struct sockaddr_storage *address) {
+ static char invalidString[] = "<invalid>";
+ static char ipString[INET6_ADDRSTRLEN + sizeof("[]:65535")];
+
+ char tmp[INET6_ADDRSTRLEN];
+ int port;
+ // TODO: getnameinfo seems to want its length parameter to be exactly
+ // sizeof(sockaddr_in) for an IPv4 address and sizeof (sockaddr_in6) for an
+ // IPv6 address. Fix getnameinfo so it accepts sizeof(sockaddr_storage), and
+ // then remove this hack.
+ int size = (address->ss_family == AF_INET) ?
+ sizeof(sockaddr_in) : sizeof(sockaddr_in6);
+ int result = getnameinfo((struct sockaddr *)address,
+ size, tmp, sizeof(tmp), NULL, 0,
+ NI_NUMERICHOST);
+
+ if (result != 0)
+ return invalidString;
+
+ if (address->ss_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) address;
+ port = ntohs(sin6->sin6_port);
+ sprintf(ipString, "[%s]:%d", tmp, port);
+ return ipString;
+ } else if (address->ss_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *) address;
+ port = ntohs(sin->sin_port);
+ sprintf(ipString, "%s:%d", tmp, port);
+ return ipString;
+ } else {
+ return invalidString;
+ }
}
/**
@@ -728,7 +837,6 @@
}
} else if (0 > result) {
- log_socket_close(handle, result);
throwSocketException(env, result);
}
poll = 0;
@@ -745,7 +853,6 @@
continue; // try again
} else if (0 > result) {
- log_socket_close(handle, result);
throwSocketException(env, result);
}
poll = 0;
@@ -756,6 +863,24 @@
}
/**
+ * Obtain the socket address family from an existing socket.
+ *
+ * @param socket the filedescriptor of the socket to examine
+ *
+ * @return an integer, the address family of the socket
+ */
+static int getSocketAddressFamily(int socket) {
+ struct sockaddr_storage ss;
+ socklen_t namelen = sizeof(ss);
+ int ret = getsockname(socket, (struct sockaddr*) &ss, &namelen);
+ if (ret != 0) {
+ return AF_UNSPEC;
+ } else {
+ return ss.ss_family;
+ }
+}
+
+/**
* A helper method, to set the connect context to a Long object.
*
* @param env pointer to the JNI library
@@ -803,6 +928,77 @@
}
/**
+ * Converts an IPv4 address to an IPv4-mapped IPv6 address. Performs no error
+ * checking.
+ *
+ * @param address the address to convert. Must contain an IPv4 address.
+ * @param outputAddress the converted address. Will contain an IPv6 address.
+ * @param mapUnspecified if true, convert 0.0.0.0 to ::ffff:0:0; if false, to ::
+ */
+static void ipv4ToMappedAddress(struct sockaddr_storage *address,
+ struct sockaddr_storage *outputAddress, bool mapUnspecified) {
+ memset(outputAddress, 0, sizeof(struct sockaddr_storage));
+ const struct sockaddr_in *sin = ((struct sockaddr_in *) address);
+ struct sockaddr_in6 *sin6 = ((struct sockaddr_in6 *) outputAddress);
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr;
+ if (sin->sin_addr.s_addr != 0 || mapUnspecified) {
+ sin6->sin6_addr.s6_addr32[2] = htonl(0xffff);
+ }
+ sin6->sin6_port = sin->sin_port;
+}
+
+/**
+ * Wrapper for connect() that converts IPv4 addresses to IPv4-mapped IPv6
+ * addresses if necessary.
+ *
+ * @param socket the filedescriptor of the socket to connect
+ * @param socketAddress the address to connect to
+ */
+static int doConnect(int socket, struct sockaddr_storage *socketAddress) {
+ struct sockaddr_storage mappedAddress;
+ struct sockaddr_storage *realAddress;
+ if (socketAddress->ss_family == AF_INET &&
+ getSocketAddressFamily(socket) == AF_INET6) {
+ ipv4ToMappedAddress(socketAddress, &mappedAddress, true);
+ realAddress = &mappedAddress;
+ } else {
+ realAddress = socketAddress;
+ }
+ int ret;
+ do {
+ ret = connect(socket, (struct sockaddr *) realAddress,
+ sizeof(struct sockaddr_storage));
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+/**
+ * Wrapper for bind() that converts IPv4 addresses to IPv4-mapped IPv6
+ * addresses if necessary.
+ *
+ * @param socket the filedescriptor of the socket to connect
+ * @param socketAddress the address to connect to
+ */
+static int doBind(int socket, struct sockaddr_storage *socketAddress) {
+ struct sockaddr_storage mappedAddress;
+ struct sockaddr_storage *realAddress;
+ if (socketAddress->ss_family == AF_INET &&
+ getSocketAddressFamily(socket) == AF_INET6) {
+ ipv4ToMappedAddress(socketAddress, &mappedAddress, false);
+ realAddress = &mappedAddress;
+ } else {
+ realAddress = socketAddress;
+ }
+ int ret;
+ do {
+ ret = bind(socket, (struct sockaddr *) realAddress,
+ sizeof(struct sockaddr_storage));
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+/**
* Establish a connection to a peer with a timeout. This function is called
* repeatedly in order to carry out the connect and to allow other tasks to
* proceed on certain platforms. The caller must first call with
@@ -823,7 +1019,7 @@
*
* @return 0, if no errors occurred, otherwise the (negative) error code.
*/
-static int sockConnectWithTimeout(int handle, struct sockaddr_in addr,
+static int sockConnectWithTimeout(int handle, struct sockaddr_storage addr,
unsigned int timeout, unsigned int step, jbyte *ctxt) {
int rc = 0;
struct timeval passedTimeout;
@@ -838,16 +1034,14 @@
context->sock = handle;
context->nfds = handle + 1;
- if (useAdbNetworking && !isLocalhost(&addr)) {
+ if (useAdbNetworkingForAddress(&addr)) {
// LOGD("+connect to address 0x%08x (via adb)",
// addr.sin_addr.s_addr);
- rc = adb_networking_connect_fd(handle, &addr);
+ rc = adb_networking_connect_fd(handle, (struct sockaddr_in *) &addr);
// LOGD("-connect ret %d errno %d (via adb)", rc, errno);
} else {
- log_socket_connect(handle, ntohl(addr.sin_addr.s_addr),
- ntohs(addr.sin_port));
/* set the socket to non-blocking */
int block = JNI_TRUE;
rc = ioctl(handle, FIONBIO, &block);
@@ -857,10 +1051,7 @@
// LOGD("+connect to address 0x%08x (via normal) on handle %d",
// addr.sin_addr.s_addr, handle);
- do {
- rc = connect(handle, (struct sockaddr *) &addr,
- sizeof(struct sockaddr));
- } while (rc < 0 && errno == EINTR);
+ rc = doConnect(handle, &addr);
// LOGD("-connect to address 0x%08x (via normal) returned %d",
// addr.sin_addr.s_addr, (int) rc);
@@ -971,6 +1162,89 @@
return SOCKERR_ARGSINVALID;
}
+
+/**
+ * Helper method to get or set socket options
+ *
+ * @param action SOCKOPT_GET to get an option, SOCKOPT_SET to set it
+ * @param socket the file descriptor of the socket to use
+ * @param ipv4Option the option value to use for an IPv4 socket
+ * @param ipv6Option the option value to use for an IPv6 socket
+ * @param optionValue the value of the socket option to get or set
+ * @param optionLength the length of the socket option to get or set
+ *
+ * @return the value of the socket call, or -1 on failure inside this function
+ *
+ * @note on internal failure, the errno variable will be set appropriately
+ */
+static int getOrSetSocketOption(int action, int socket, int ipv4Option,
+ int ipv6Option, void *optionValue, socklen_t *optionLength) {
+ int option;
+ int protocol;
+ int family = getSocketAddressFamily(socket);
+ switch (family) {
+ case AF_INET:
+ option = ipv4Option;
+ protocol = IPPROTO_IP;
+ break;
+ case AF_INET6:
+ option = ipv6Option;
+ protocol = IPPROTO_IPV6;
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+ if (action == SOCKOPT_GET) {
+ return getsockopt(socket, protocol, option, &optionValue, optionLength);
+ } else if (action == SOCKOPT_SET) {
+ return setsockopt(socket, protocol, option, &optionValue,
+ *optionLength);
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+/*
+ * Find the interface index that was set for this socket by the IP_MULTICAST_IF
+ * or IPV6_MULTICAST_IF socket option.
+ *
+ * @param socket the socket to examine
+ *
+ * @return the interface index, or -1 on failure
+ *
+ * @note on internal failure, the errno variable will be set appropriately
+ */
+static int interfaceIndexFromMulticastSocket(int socket) {
+ int family = getSocketAddressFamily(socket);
+ socklen_t requestLength;
+ int interfaceIndex;
+ int result;
+ if (family == AF_INET) {
+ // IP_MULTICAST_IF returns a pointer to a struct ip_mreqn.
+ struct ip_mreqn tempRequest;
+ requestLength = sizeof(tempRequest);
+ result = getsockopt(socket, IPPROTO_IP, IP_MULTICAST_IF, &tempRequest,
+ &requestLength);
+ interfaceIndex = tempRequest.imr_ifindex;
+ } else if (family == AF_INET6) {
+ // IPV6_MULTICAST_IF returns a pointer to an integer.
+ requestLength = sizeof(interfaceIndex);
+ result = getsockopt(socket, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ &interfaceIndex, &requestLength);
+ } else {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (result == 0)
+ return interfaceIndex;
+ else
+ return -1;
+}
+
+
/**
* Join/Leave the nominated multicast group on the specified socket.
* Implemented by setting the multicast 'add membership'/'drop membership'
@@ -994,103 +1268,112 @@
*/
static void mcastAddDropMembership (JNIEnv * env, int handle, jobject optVal,
int ignoreIF, int setSockOptVal) {
+ struct sockaddr_storage sockaddrP;
int result;
- struct ip_mreq ipmreqP;
- struct sockaddr_in sockaddrP;
- int length = sizeof(struct ip_mreq);
- socklen_t lengthIF = sizeof(struct sockaddr_in);
+ // By default, let the system decide which interface to use.
+ int interfaceIndex = 0;
/*
- * JNI objects needed to access the information in the optVal oject
- * passed in. The object passed in is a GenericIPMreq object
- */
- jclass cls;
- jfieldID multiaddrID;
- jfieldID interfaceAddrID;
- jobject multiaddr;
- jobject interfaceAddr;
-
- /*
- * check whether we are getting an InetAddress or an Generic IPMreq, for now
- * we support both so that we will not break the tests
+ * Check whether we are getting an InetAddress or an Generic IPMreq. For now
+ * we support both so that we will not break the tests. If an InetAddress
+ * is passed in, only support IPv4 as obtaining an interface from an
+ * InetAddress is complex and should be done by the Java caller.
*/
if (env->IsInstanceOf (optVal, gCachedFields.iaddr_class)) {
+ /*
+ * optVal is an InetAddress. Construct a multicast request structure
+ * from this address. Support IPv4 only.
+ */
+ struct ip_mreqn multicastRequest;
+ socklen_t length = sizeof(multicastRequest);
+ memset(&multicastRequest, 0, length);
- ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
+ // If ignoreIF is false, determine the index of the interface to use.
if (!ignoreIF) {
-
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF, &sockaddrP,
- &lengthIF);
-
- if (0 != result) {
- throwSocketException (env, convertError(errno));
+ interfaceIndex = interfaceIndexFromMulticastSocket(handle);
+ multicastRequest.imr_ifindex = interfaceIndex;
+ if (interfaceIndex == -1) {
+ throwSocketException(env, convertError(errno));
return;
}
-
- memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
}
+ // Convert the inetAddress to an IPv4 address structure.
result = inetAddressToSocketAddress(env, optVal, 0, &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ if (result < 0) // Exception has already been thrown.
+ return;
+ if (sockaddrP.ss_family != AF_INET) {
+ throwSocketException(env, SOCKERR_BADAF);
return;
}
+ struct sockaddr_in *sin = (struct sockaddr_in *) &sockaddrP;
+ multicastRequest.imr_multiaddr = sin->sin_addr;
- memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
-
- result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ result = setsockopt(handle, IPPROTO_IP, setSockOptVal,
+ &multicastRequest, length);
if (0 != result) {
throwSocketException (env, convertError(errno));
return;
}
-
} else {
+ /*
+ * optVal is a GenericIPMreq object. Extract the relevant fields from
+ * it and construct a multicast request structure from these. Support
+ * both IPv4 and IPv6.
+ */
+ jclass cls;
+ jfieldID multiaddrID;
+ jfieldID interfaceIdxID;
+ jobject multiaddr;
- /* we need the multicast address regardless of the type of address */
+ // Get the multicast address to join or leave.
cls = env->GetObjectClass(optVal);
multiaddrID = env->GetFieldID(cls, "multiaddr", "Ljava/net/InetAddress;");
multiaddr = env->GetObjectField(optVal, multiaddrID);
- result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- return;
+ // Get the interface index to use.
+ if (! ignoreIF) {
+ interfaceIdxID = env->GetFieldID(cls, "interfaceIdx", "I");
+ interfaceIndex = env->GetIntField(optVal, interfaceIdxID);
}
- memcpy(&(ipmreqP.imr_multiaddr.s_addr), &(sockaddrP.sin_addr), 4);
+ result = inetAddressToSocketAddress(env, multiaddr, 0, &sockaddrP);
+ if (result < 0) // Exception has already been thrown.
+ return;
- /* we need to use an IP_MREQ as it is an IPV4 address */
- interfaceAddrID = env->GetFieldID(cls, "interfaceAddr",
- "Ljava/net/InetAddress;");
- interfaceAddr = env->GetObjectField(optVal, interfaceAddrID);
-
- ipmreqP.imr_interface.s_addr = htonl(INADDR_ANY);
-
- /*
- * if an interfaceAddr was passed then use that value, otherwise set the
- * interface to all 0 to indicate the system should select the interface
- * used
- */
- if (!ignoreIF) {
- if (NULL != interfaceAddr) {
-
- result = inetAddressToSocketAddress(env, interfaceAddr, 0,
- &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- return;
- }
-
- memcpy(&(ipmreqP.imr_interface.s_addr), &(sockaddrP.sin_addr), 4);
-
- }
+ struct ip_mreqn ipv4Request;
+ struct ipv6_mreq ipv6Request;
+ void *multicastRequest;
+ socklen_t requestLength;
+ int level;
+ int family = getSocketAddressFamily(handle);
+ switch (family) {
+ case AF_INET:
+ requestLength = sizeof(ipv4Request);
+ memset(&ipv4Request, 0, requestLength);
+ ipv4Request.imr_multiaddr =
+ ((struct sockaddr_in *) &sockaddrP)->sin_addr;
+ ipv4Request.imr_ifindex = interfaceIndex;
+ multicastRequest = &ipv4Request;
+ level = IPPROTO_IP;
+ break;
+ case AF_INET6:
+ requestLength = sizeof(ipv6Request);
+ memset(&ipv6Request, 0, requestLength);
+ ipv6Request.ipv6mr_multiaddr =
+ ((struct sockaddr_in6 *) &sockaddrP)->sin6_addr;
+ ipv6Request.ipv6mr_interface = interfaceIndex;
+ multicastRequest = &ipv6Request;
+ level = IPPROTO_IPV6;
+ break;
+ default:
+ throwSocketException (env, SOCKERR_BADAF);
+ return;
}
/* join/drop the multicast address */
- result = setsockopt(handle, IPPROTO_IP, setSockOptVal, &ipmreqP, length);
+ result = setsockopt(handle, level, setSockOptVal, multicastRequest,
+ requestLength);
if (0 != result) {
throwSocketException (env, convertError(errno));
return;
@@ -1339,38 +1622,48 @@
}
+/**
+ * Helper function to create a socket of the specified type and bind it to a
+ * Java file descriptor.
+ *
+ * @param fileDescriptor the file descriptor to bind the socket to
+ * @param type the socket type to create, e.g., SOCK_STREAM
+ *
+ * @return the socket file descriptor, or -1 on failure
+ *
+ */
+static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor,
+ int type) {
+ if (fileDescriptor == NULL) {
+ throwNullPointerException(env);
+ errno = EBADF;
+ return -1;
+ }
+
+ int sock;
+ sock = socket(PF_INET6, type, 0);
+ if (sock < 0 && errno == EAFNOSUPPORT) {
+ sock = socket(PF_INET, type, 0);
+ }
+ if (sock < 0) {
+ int err = convertError(errno);
+ throwSocketException(env, err);
+ }
+ jniSetFileDescriptorOfFD(env, fileDescriptor, sock);
+ return sock;
+}
+
+
static void osNetworkSystem_createSocketImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createSocketImpl");
-
- int ret = socket(PF_INET, SOCK_STREAM, 0);
-
- if (ret < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
- return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
-
- return;
+ createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
}
static void osNetworkSystem_createDatagramSocketImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createDatagramSocketImpl");
-
- int ret = socket(PF_INET, SOCK_DGRAM, 0);
-
- if (ret < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
- return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, ret);
-
- return;
+ createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
}
static jint osNetworkSystem_readSocketDirectImpl(JNIEnv* env, jclass clazz,
@@ -1379,7 +1672,7 @@
// LOGD("ENTER readSocketDirectImpl");
int handle;
- jbyte *message = (jbyte *)address;
+ jbyte *message = (jbyte *)address + offset;
int result, ret, localCount;
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -1405,11 +1698,9 @@
return -1;
} else if (ret == -1) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
- add_recv_stats(handle, ret);
return ret;
}
@@ -1437,7 +1728,7 @@
}
result = osNetworkSystem_readSocketDirectImpl(env, clazz, fileDescriptor,
- (jint) message, offset, count, timeout);
+ (jint) message, 0, localCount, timeout);
if (result > 0) {
env->SetByteArrayRegion(data, offset, result, (jbyte *)message);
@@ -1455,7 +1746,7 @@
// LOGD("ENTER writeSocketDirectImpl");
int handle;
- jbyte *message = (jbyte *)address;
+ jbyte *message = (jbyte *)address + offset;
int result = 0, sent = 0;
if (count <= 0) {
@@ -1472,7 +1763,6 @@
result = send(handle, (jbyte *) message, (int) count, SOCKET_NOFLAGS);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
if (SOCKERR_WOULDBLOCK == err){
jclass socketExClass,errorCodeExClass;
@@ -1499,7 +1789,7 @@
if (!socketExConstructor) {
return 0;
}
- socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
+ socketEx = env->NewObject(socketExClass, socketExConstructor, errorMessageString);
socketExCauseMethod = env->GetMethodID(socketExClass,"initCause","(Ljava/lang/Throwable;)Ljava/lang/Throwable;");
env->CallObjectMethod(socketEx,socketExCauseMethod,errorCodeEx);
env->Throw((jthrowable)socketEx);
@@ -1509,7 +1799,6 @@
return 0;
}
- add_send_stats(handle, result);
return result;
}
@@ -1539,13 +1828,13 @@
env->GetByteArrayRegion(data, offset, count, message);
result = osNetworkSystem_writeSocketDirectImpl(env, clazz, fileDescriptor,
- (jint) message, offset, count);
+ (jint) message, 0, count);
if (( jbyte *)message != internalBuffer) {
- free(( jbyte *)message);
+ free(( jbyte *)message);
}
#undef INTERNAL_SEND_BUFFER_MAX
- return result;
+ return result;
}
static void osNetworkSystem_setNonBlockingImpl(JNIEnv* env, jclass clazz,
@@ -1581,36 +1870,25 @@
int handle;
int result = 0;
- struct sockaddr_in address;
+ struct sockaddr_storage address;
jbyte *context = NULL;
- memset(&address, 0, sizeof(address));
-
- address.sin_family = AF_INET;
-
- result = inetAddressToSocketAddress(env, inetAddr, port,
- (struct sockaddr_in *) &address);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ result = inetAddressToSocketAddress(env, inetAddr, port, &address);
+ if (result < 0)
return result;
- }
// Check if we're using adb networking and redirect in case it is used.
- if (useAdbNetworking && !isLocalhost(&address)) {
+ if (useAdbNetworkingForAddress(&address)) {
return osNetworkSystem_connectSocketImpl(env, clazz, fileDescriptor,
trafficClass, inetAddr, port);
}
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return -1;
}
- address.sin_port = htons(port);
-
context = (jbyte *)env->GetPrimitiveArrayCritical(passContext, NULL);
switch (step) {
@@ -1651,7 +1929,7 @@
int result = 0;
int handle;
- struct sockaddr_in address;
+ struct sockaddr_storage address;
jbyte *context = NULL;
int remainingTimeout = timeout;
int passedTimeout = 0;
@@ -1664,53 +1942,117 @@
finishTime = time_msec_clock() + (int) timeout;
}
-
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
- } else {
- result = inetAddressToSocketAddress(env, inetAddr, remotePort,
- (struct sockaddr_in *) &address);
+ }
- if (result < 0) {
+ result = inetAddressToSocketAddress(env, inetAddr, remotePort, &address);
+ if (result < 0) // Exception has already been thrown.
+ return;
+
+ // Check if we're using adb networking and redirect in case it is used.
+ if (useAdbNetworkingForAddress(&address)) {
+ int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
+ fileDescriptor, trafficClass, inetAddr, remotePort);
+ if (retVal != 0) {
throwSocketException(env, SOCKERR_BADSOCKET);
- return;
}
+ return;
+ }
- // Check if we're using adb networking and redirect in case it is used.
- if (useAdbNetworking && !isLocalhost(&address)) {
- int retVal = osNetworkSystem_connectSocketImpl(env, clazz,
- fileDescriptor, trafficClass, inetAddr, remotePort);
- if (retVal != 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
- }
- return;
+ /*
+ * we will be looping checking for when we are connected so allocate
+ * the descriptor sets that we will use
+ */
+ context =(jbyte *) malloc(sizeof(struct selectFDSet));
+ if (NULL == context) {
+ throwSocketException(env, SOCKERR_NOBUFFERS);
+ return;
+ }
+
+ result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
+ if (0 == result) {
+ /* ok we connected right away so we are done */
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
+ goto bail;
+ } else if (result != SOCKERR_NOTCONNECTED) {
+ sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
+ context);
+ /* we got an error other than NOTCONNECTED so we cannot continue */
+ if (SOCKERR_EACCES == result) {
+ jniThrowException(env, "java/lang/SecurityException",
+ netLookupErrorString(result));
+ } else {
+ throwSocketException(env, result);
+ }
+ goto bail;
+ }
+
+ while (SOCKERR_NOTCONNECTED == result) {
+ passedTimeout = remainingTimeout;
+
+ /*
+ * ok now try and connect. Depending on the platform this may sleep
+ * for up to passedTimeout milliseconds
+ */
+ result = sockConnectWithTimeout(handle, address, passedTimeout,
+ SOCKET_STEP_CHECK, context);
+
+ /*
+ * now check if the socket is still connected.
+ * Do it here as some platforms seem to think they
+ * are connected if the socket is closed on them.
+ */
+ handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
+ if (handle == 0 || handle == -1) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ throwSocketException(env, SOCKERR_BADSOCKET);
+ goto bail;
}
/*
- * we will be looping checking for when we are connected so allocate
- * the descriptor sets that we will use
+ * check if we are now connected,
+ * if so we can finish the process and return
*/
- context =(jbyte *) malloc(sizeof(struct selectFDSet));
-
- if (NULL == context) {
- throwSocketException(env, SOCKERR_NOBUFFERS);
- return;
+ if (0 == result) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ goto bail;
}
- result = sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_START, context);
- if (0 == result) {
- /* ok we connected right away so we are done */
- sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE, context);
- goto bail;
- } else if (result != SOCKERR_NOTCONNECTED) {
- log_socket_close(handle, result);
- sockConnectWithTimeout(handle, address, 0, SOCKET_STEP_DONE,
- context);
- /* we got an error other than NOTCONNECTED so we cannot continue */
- if (SOCKERR_EACCES == result) {
+ /*
+ * if the error is SOCKERR_NOTCONNECTED then we have not yet
+ * connected and we may not be done yet
+ */
+ if (SOCKERR_NOTCONNECTED == result) {
+ /* check if the timeout has expired */
+ if (hasTimeout) {
+ remainingTimeout = finishTime - time_msec_clock();
+ if (remainingTimeout <= 0) {
+ sockConnectWithTimeout(handle, address, 0,
+ SOCKET_STEP_DONE, context);
+ jniThrowException(env,
+ "java/net/SocketTimeoutException",
+ netLookupErrorString(result));
+ goto bail;
+ }
+ } else {
+ remainingTimeout = 100;
+ }
+ } else {
+ sockConnectWithTimeout(handle, address, remainingTimeout,
+ SOCKET_STEP_DONE, context);
+ if ((SOCKERR_CONNRESET == result) ||
+ (SOCKERR_CONNECTION_REFUSED == result) ||
+ (SOCKERR_ADDRNOTAVAIL == result) ||
+ (SOCKERR_ADDRINUSE == result) ||
+ (SOCKERR_ENETUNREACH == result)) {
+ jniThrowException(env, "java/net/ConnectException",
+ netLookupErrorString(result));
+ } else if (SOCKERR_EACCES == result) {
jniThrowException(env, "java/lang/SecurityException",
netLookupErrorString(result));
} else {
@@ -1718,81 +2060,6 @@
}
goto bail;
}
-
- while (SOCKERR_NOTCONNECTED == result) {
- passedTimeout = remainingTimeout;
-
- /*
- * ok now try and connect. Depending on the platform this may sleep
- * for up to passedTimeout milliseconds
- */
- result = sockConnectWithTimeout(handle, address, passedTimeout,
- SOCKET_STEP_CHECK, context);
-
- /*
- * now check if the socket is still connected.
- * Do it here as some platforms seem to think they
- * are connected if the socket is closed on them.
- */
- handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- if (handle == 0 || handle == -1) {
- sockConnectWithTimeout(handle, address, 0,
- SOCKET_STEP_DONE, context);
- throwSocketException(env, SOCKERR_BADSOCKET);
- goto bail;
- }
-
- /*
- * check if we are now connected,
- * if so we can finish the process and return
- */
- if (0 == result) {
- sockConnectWithTimeout(handle, address, 0,
- SOCKET_STEP_DONE, context);
- goto bail;
- }
-
- /*
- * if the error is SOCKERR_NOTCONNECTED then we have not yet
- * connected and we may not be done yet
- */
- if (SOCKERR_NOTCONNECTED == result) {
- /* check if the timeout has expired */
- if (hasTimeout) {
- remainingTimeout = finishTime - time_msec_clock();
- if (remainingTimeout <= 0) {
- log_socket_close(handle, result);
- sockConnectWithTimeout(handle, address, 0,
- SOCKET_STEP_DONE, context);
- jniThrowException(env,
- "java/net/SocketTimeoutException",
- netLookupErrorString(result));
- goto bail;
- }
- } else {
- remainingTimeout = 100;
- }
- } else {
- log_socket_close(handle, result);
- sockConnectWithTimeout(handle, address, remainingTimeout,
- SOCKET_STEP_DONE, context);
- if ((SOCKERR_CONNRESET == result) ||
- (SOCKERR_CONNECTION_REFUSED == result) ||
- (SOCKERR_ADDRNOTAVAIL == result) ||
- (SOCKERR_ADDRINUSE == result) ||
- (SOCKERR_ENETUNREACH == result)) {
- jniThrowException(env, "java/net/ConnectException",
- netLookupErrorString(result));
- } else if (SOCKERR_EACCES == result) {
- jniThrowException(env, "java/lang/SecurityException",
- netLookupErrorString(result));
- } else {
- throwSocketException(env, result);
- }
- goto bail;
- }
- }
}
bail:
@@ -1807,37 +2074,25 @@
jobject fileDescriptor, jint trafficClass, jobject inetAddr, jint port) {
//LOGD("ENTER direct-call connectSocketImpl\n");
- struct sockaddr_in address;
+ struct sockaddr_storage address;
int ret;
int handle;
- jbyteArray java_in_addr;
- memset(&address, 0, sizeof(address));
-
- address.sin_family = AF_INET;
-
- ret = inetAddressToSocketAddress(env, inetAddr, port,
- (struct sockaddr_in *) &address);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddr, port, &address);
+ if (ret < 0)
return ret;
- }
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return -1;
}
- address.sin_port = htons(port);
-
- if (useAdbNetworking && !isLocalhost(&address)) {
+ if (useAdbNetworkingForAddress(&address)) {
// LOGD("+connect to address 0x%08x port %d (via adb)",
// address.sin_addr.s_addr, (int) port);
- ret = adb_networking_connect_fd(handle, &address);
+ ret = adb_networking_connect_fd(handle, (struct sockaddr_in *) &address);
// LOGD("-connect ret %d errno %d (via adb)", ret, errno);
} else {
@@ -1866,27 +2121,21 @@
jobject fileDescriptor, jint port, jobject inetAddress) {
// LOGD("ENTER socketBindImpl");
- struct sockaddr_in sockaddress;
+ struct sockaddr_storage sockaddress;
int ret;
int handle;
- ret = inetAddressToSocketAddress(env, inetAddress, port,
- (struct sockaddr_in *) &sockaddress);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
+ if (ret < 0)
return;
- }
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
}
- ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
-
+ ret = doBind(handle, &sockaddress);
if (ret < 0) {
jniThrowException(env, "java/net/BindException",
netLookupErrorString(convertError(errno)));
@@ -1912,7 +2161,6 @@
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
@@ -1928,9 +2176,8 @@
int result;
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
@@ -1943,7 +2190,6 @@
} else if (SOCKERR_INTERRUPTED == result) {
continue;
} else if (0 > result) {
- log_socket_close(handle, result);
throwSocketException(env, result);
return 0;
}
@@ -1953,11 +2199,9 @@
if (0 > result) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
- add_recv_stats(handle, result);
return result;
}
@@ -1965,10 +2209,7 @@
jobject fdServer, jobject newSocket, jobject fdnewSocket, jint timeout) {
// LOGD("ENTER acceptSocketImpl");
- union {
- struct sockaddr address;
- struct sockaddr_in in_address;
- } sa;
+ struct sockaddr_storage sa;
int ret;
int retFD;
@@ -1982,55 +2223,47 @@
}
result = pollSelectWait(env, fdServer, timeout, SELECT_READ_TYPE);
-
if (0 > result) {
return;
}
handle = jniGetFDFromFileDescriptor(env, fdServer);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
}
do {
addrlen = sizeof(sa);
- ret = accept(handle, &(sa.address), &addrlen);
+ ret = accept(handle, (struct sockaddr *) &sa, &addrlen);
} while (ret < 0 && errno == EINTR);
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
retFD = ret;
- /* For AF_INET / inetOrLocal == true only: put
- * peer address and port in instance variables
- * We don't bother for UNIX domain sockets, since most peers are
- * anonymous anyway
+ /*
+ * For network sockets, put the peer address and port in instance variables.
+ * We don't bother to do this for UNIX domain sockets, since most peers are
+ * anonymous anyway.
*/
- if (sa.address.sa_family == AF_INET) {
- // inetOrLocal should also be true
-
- jobject inetAddress;
-
- inetAddress = structInToInetAddress(env, &(sa.in_address.sin_addr));
-
- if (inetAddress == NULL) {
+ if (sa.ss_family == AF_INET || sa.ss_family == AF_INET6) {
+ jobject inetAddress = socketAddressToInetAddress(env, &sa);
+ if (ret == -1) {
close(retFD);
- newSocket = NULL;
+ newSocket = NULL; // Exception has already been thrown.
return;
}
env->SetObjectField(newSocket,
gCachedFields.socketimpl_address, inetAddress);
- env->SetIntField(newSocket, gCachedFields.socketimpl_port,
- ntohs(sa.in_address.sin_port));
+ int port = getSocketAddressPort(&sa);
+ env->SetIntField(newSocket, gCachedFields.socketimpl_port, port);
}
jniSetFileDescriptorOfFD(env, fdnewSocket, retFD);
@@ -2066,7 +2299,6 @@
result = send(handle, (jbyte *) &value, 1, MSG_OOB);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
}
@@ -2077,20 +2309,16 @@
int handle = jniGetFDFromFileDescriptor(env, fd);
- struct sockaddr_in sockAddr;
+ struct sockaddr_storage sockAddr;
int ret;
ret = inetAddressToSocketAddress(env, inetAddress, port, &sockAddr);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ if (ret < 0) // Exception has already been thrown.
return;
- }
- log_socket_connect(handle, ntohl(sockAddr.sin_addr.s_addr), port);
- int result = connect(handle, (struct sockaddr *)&sockAddr, sizeof(sockAddr));
- if (result < 0) {
+
+ ret = doConnect(handle, &sockAddr);
+ if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
}
@@ -2101,18 +2329,13 @@
int handle = jniGetFDFromFileDescriptor(env, fd);
- struct sockaddr_in *sockAddr;
- socklen_t sockAddrLen = sizeof(struct sockaddr_in);
- sockAddr = (struct sockaddr_in *) malloc(sockAddrLen);
- memset(sockAddr, 0, sockAddrLen);
+ struct sockaddr_storage sockAddr;
+ memset(&sockAddr, 0, sizeof(sockAddr));
+ sockAddr.ss_family = AF_UNSPEC;
- sockAddr->sin_family = AF_UNSPEC;
- int result = connect(handle, (struct sockaddr *)sockAddr, sockAddrLen);
- free(sockAddr);
-
+ int result = doConnect(handle, &sockAddr);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
}
@@ -2122,29 +2345,23 @@
jobject inetAddress) {
// LOGD("ENTER socketBindImpl2");
- struct sockaddr_in sockaddress;
+ struct sockaddr_storage sockaddress;
int ret;
int handle;
- ret = inetAddressToSocketAddress(env, inetAddress, port,
- (struct sockaddr_in *) &sockaddress);
-
- if (ret < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddress);
+ if (ret < 0) // Exception has already been thrown.
return 0;
- }
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
- ret = bind(handle, (const sockaddr*)&sockaddress, sizeof(sockaddress));
-
+ ret = doBind(handle, &sockaddress);
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
jniThrowException(env, "java/net/BindException", netLookupErrorString(err));
return 0;
}
@@ -2164,30 +2381,29 @@
}
int handle = jniGetFDFromFileDescriptor(env, fd);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
- struct sockaddr_in sockAddr;
+ struct sockaddr_storage sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
-
- int length = recvfrom(handle, NULL, 0, MSG_PEEK,
- (struct sockaddr *)&sockAddr, &sockAddrLen);
-
+ ssize_t length;
+ do {
+ length = recvfrom(handle, NULL, 0, MSG_PEEK,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+ } while (length < 0 && errno == EINTR);
if (length < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
- if (socketAddressToInetAddress(env, &sockAddr, sender, &port) < 0) {
- throwIOExceptionStr(env, "Address conversion failed");
+ sender = socketAddressToInetAddress(env, &sockAddr);
+ if (sender == NULL) // Exception has already been thrown.
return -1;
- }
- add_recv_stats(handle, length);
+
+ port = getSocketAddressPort(&sockAddr);
return port;
}
@@ -2202,44 +2418,41 @@
}
int handle = jniGetFDFromFileDescriptor(env, fd);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
- struct sockaddr_in sockAddr;
+ struct sockaddr_storage sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
int mode = peek ? MSG_PEEK : 0;
- int actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
- (struct sockaddr *)&sockAddr, &sockAddrLen);
-
+ ssize_t actualLength;
+ do {
+ actualLength = recvfrom(handle, (char*)(address + offset), length, mode,
+ (struct sockaddr *)&sockAddr, &sockAddrLen);
+ } while (actualLength < 0 && errno == EINTR);
if (actualLength < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
if (packet != NULL) {
- int port = ntohs(sockAddr.sin_port);
- jbyteArray addr = env->NewByteArray(sizeof(struct in_addr));
- if ((structInToJavaAddress(env, &sockAddr.sin_addr, addr)) < 0) {
- jniThrowException(env, "java/net/SocketException",
- "Could not set address of packet.");
+ jbyteArray addr = socketAddressToAddressBytes(env, &sockAddr);
+ if (addr == NULL) // Exception has already been thrown.
return 0;
- }
+ int port = getSocketAddressPort(&sockAddr);
jobject sender = env->CallStaticObjectMethod(
gCachedFields.iaddr_class, gCachedFields.iaddr_getbyaddress,
addr);
env->SetObjectField(packet, gCachedFields.dpack_address, sender);
env->SetIntField(packet, gCachedFields.dpack_port, port);
- env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
+ env->SetIntField(packet, gCachedFields.dpack_length,
+ (jint) actualLength);
}
- add_recv_stats(handle, actualLength);
- return actualLength;
+ return (jint) actualLength;
}
static jint osNetworkSystem_receiveDatagramImpl(JNIEnv* env, jclass clazz,
@@ -2256,7 +2469,7 @@
}
int actualLength = osNetworkSystem_receiveDatagramDirectImpl(env, clazz, fd,
- packet, (jint)bytes, offset, localLength, receiveTimeout, peek);
+ packet, (jint)bytes, 0, localLength, receiveTimeout, peek);
if (actualLength > 0) {
env->SetByteArrayRegion(data, offset, actualLength, bytes);
@@ -2297,7 +2510,6 @@
if ( packet != NULL) {
env->SetIntField(packet, gCachedFields.dpack_length, actualLength);
}
- add_recv_stats(handle, actualLength);
return actualLength;
}
@@ -2315,7 +2527,7 @@
}
int actualLength = osNetworkSystem_recvConnectedDatagramDirectImpl(env,
- clazz, fd, packet, (jint)bytes, offset, localLength,
+ clazz, fd, packet, (jint)bytes, 0, localLength,
receiveTimeout, peek);
if (actualLength > 0) {
@@ -2331,8 +2543,6 @@
jboolean bindToDevice, jint trafficClass, jobject inetAddress) {
// LOGD("ENTER sendDatagramDirectImpl");
- int result = 0;
-
int handle = jniGetFDFromFileDescriptor(env, fd);
if (handle == 0 || handle == -1) {
@@ -2340,29 +2550,28 @@
return 0;
}
- struct sockaddr_in receiver;
-
+ struct sockaddr_storage receiver;
if (inetAddressToSocketAddress(env, inetAddress, port, &receiver) < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ // Exception has already been thrown.
return 0;
}
- result = sendto(handle, (char*)(address + offset), length, SOCKET_NOFLAGS,
- (struct sockaddr*)&receiver, sizeof(receiver));
-
+ ssize_t result = 0;
+ do {
+ result = sendto(handle, (char*)(address + offset), length,
+ SOCKET_NOFLAGS, (struct sockaddr*)&receiver, sizeof(receiver));
+ } while (result < 0 && errno == EINTR);
if (result < 0) {
int err = convertError(errno);
if ((SOCKERR_CONNRESET == err)
|| (SOCKERR_CONNECTION_REFUSED == err)) {
return 0;
} else {
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
}
- add_send_stats(handle, result);
- return result;
+ return (jint) result;
}
static jint osNetworkSystem_sendDatagramImpl(JNIEnv* env, jclass clazz,
@@ -2398,12 +2607,10 @@
if ((SOCKERR_CONNRESET == err) || (SOCKERR_CONNECTION_REFUSED == err)) {
return 0;
} else {
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
}
- add_send_stats(handle, length);
return result;
}
@@ -2424,23 +2631,11 @@
jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createServerStreamSocketImpl");
- if (fileDescriptor == NULL) {
- throwNullPointerException(env);
+ int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_STREAM);
+ if (handle < 0)
return;
- }
-
- int handle = socket(PF_INET, SOCK_STREAM, 0);
-
- if (handle < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
- return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
int value = 1;
-
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
}
@@ -2448,18 +2643,11 @@
jclass clazz, jobject fileDescriptor, jboolean preferIPv4Stack) {
// LOGD("ENTER createMulticastSocketImpl");
- int handle = socket(PF_INET, SOCK_DGRAM, 0);
-
- if (handle < 0) {
- int err = convertError(errno);
- throwSocketException(env, err);
+ int handle = createSocketFileDescriptor(env, fileDescriptor, SOCK_DGRAM);
+ if (handle < 0)
return;
- }
-
- jniSetFileDescriptorOfFD(env, fileDescriptor, handle);
int value = 1;
-
// setsockopt(handle, SOL_SOCKET, SO_REUSEPORT, &value, sizeof(jbyte));
setsockopt(handle, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int));
}
@@ -2505,7 +2693,6 @@
* to the Java input stream
*/
if (0 < result) {
- add_recv_stats(handle, result);
return result;
} else if (0 == result) {
return -1;
@@ -2516,7 +2703,6 @@
netLookupErrorString(SOCKERR_TIMEOUT));
} else {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
}
return 0;
@@ -2560,7 +2746,6 @@
}
env->ReleaseByteArrayElements(data, message, 0);
int err = convertError(result);
- log_socket_close(handle, err);
throwSocketException(env, err);
return 0;
}
@@ -2568,7 +2753,6 @@
}
env->ReleaseByteArrayElements(data, message, 0);
- add_send_stats(handle, sent);
return sent;
}
@@ -2590,7 +2774,6 @@
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
@@ -2613,7 +2796,6 @@
if (ret < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
return;
}
@@ -2625,26 +2807,19 @@
// LOGD("ENTER sendDatagramImpl2");
jbyte *message;
- jbyte nhostAddrBytes[4];
unsigned short nPort;
- int result = 0, sent = 0;
+ int ret = 0, sent = 0;
int handle = 0;
- struct sockaddr_in sockaddrP;
+ struct sockaddr_storage sockaddrP;
if (inetAddress != NULL) {
-
- result = inetAddressToSocketAddress(env, inetAddress, port,
- (struct sockaddr_in *) &sockaddrP);
-
- if (result < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ ret = inetAddressToSocketAddress(env, inetAddress, port, &sockaddrP);
+ if (ret < 0) // Exception has already been thrown.
return 0;
- }
handle = jniGetFDFromFileDescriptor(env, fd);
-
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return 0;
}
}
@@ -2663,18 +2838,19 @@
if (handle == 0 || handle == -1) {
throwSocketException(env,
- sent == 0 ? SOCKERR_BADSOCKET : SOCKERR_INTERRUPTED);
+ sent == 0 ? SOCKERR_BADDESC : SOCKERR_INTERRUPTED);
free(message);
return 0;
}
- result = sendto(handle, (char *) (message + sent),
- (int) (length - sent), SOCKET_NOFLAGS,
- (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
-
+ ssize_t result;
+ do {
+ result = sendto(handle, (char *) (message + sent),
+ (int) (length - sent), SOCKET_NOFLAGS,
+ (struct sockaddr *) &sockaddrP, sizeof(sockaddrP));
+ } while (result < 0 && errno == EINTR);
if (result < 0) {
int err = convertError(errno);
- log_socket_close(handle, err);
throwSocketException(env, err);
free(message);
return 0;
@@ -2684,7 +2860,6 @@
}
free(message);
- add_send_stats(handle, sent);
return sent;
}
@@ -2757,10 +2932,10 @@
}
if (0 < result) {
- /*output the result to a int array*/
- flagArray = env->GetIntArrayElements(outFlags, &isCopy);
+ /*output the result to a int array*/
+ flagArray = env->GetIntArrayElements(outFlags, &isCopy);
- for (val=0; val<countReadC; val++) {
+ for (val=0; val<countReadC; val++) {
gotFD = env->GetObjectArrayElement(readFDArray,val);
handle = jniGetFDFromFileDescriptor(env, gotFD);
@@ -2799,33 +2974,30 @@
jclass clazz, jobject fileDescriptor, jboolean preferIPv6Addresses) {
// LOGD("ENTER getSocketLocalAddressImpl");
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
memset(&addr, 0, addrLen);
+
int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
- int result;
-
if (handle == 0 || handle == -1) {
throwSocketException(env, SOCKERR_UNKNOWNSOCKET);
return NULL;
}
+ int result;
result = getsockname(handle, (struct sockaddr *)&addr, &addrLen);
// Spec says ignore all errors
-
- return structInToInetAddress(env, &(addr.sin_addr));
-
+ return socketAddressToInetAddress(env, &addr);
}
static jint osNetworkSystem_getSocketLocalPortImpl(JNIEnv* env, jclass clazz,
jobject fileDescriptor, jboolean preferIPv6Addresses) {
// LOGD("ENTER getSocketLocalPortImpl");
- struct sockaddr_in addr;
+ struct sockaddr_storage addr;
socklen_t addrLen = sizeof(addr);
int handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
@@ -2842,7 +3014,7 @@
// The java spec does not indicate any exceptions on this call
return 0;
} else {
- return ntohs(addr.sin_port);
+ return getSocketAddressPort(&addr);
}
}
@@ -2856,12 +3028,12 @@
unsigned char byteValue = 0;
socklen_t byteSize = sizeof(unsigned char);
int result;
- struct sockaddr_in sockVal;
+ struct sockaddr_storage sockVal;
socklen_t sockSize = sizeof(sockVal);
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return NULL;
}
@@ -2896,7 +3068,9 @@
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return newJavaLangByte(env, 0);
}
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteValue, &byteSize);
+ result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS, &byteValue,
+ &byteSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -2912,7 +3086,42 @@
throwSocketException(env, convertError(errno));
return NULL;
}
- return structInToInetAddress(env, &(sockVal.sin_addr));
+ // This option is IPv4-only.
+ sockVal.ss_family = AF_INET;
+ return socketAddressToInetAddress(env, &sockVal);
+ }
+ case JAVASOCKOPT_IP_MULTICAST_IF2: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return NULL;
+ }
+ struct ip_mreqn multicastRequest;
+ int interfaceIndex;
+ socklen_t optionLength;
+ int addressFamily = getSocketAddressFamily(handle);
+ switch (addressFamily) {
+ case AF_INET:
+ optionLength = sizeof(multicastRequest);
+ result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
+ &multicastRequest, &optionLength);
+ if (result == 0)
+ interfaceIndex = multicastRequest.imr_ifindex;
+ break;
+ case AF_INET6:
+ optionLength = sizeof(interfaceIndex);
+ result = getsockopt(handle, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+ &interfaceIndex, &optionLength);
+ break;
+ default:
+ throwSocketException(env, SOCKERR_BADAF);
+ return NULL;
+ }
+
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return NULL;
+ }
+
+ return newJavaLangInteger(env, interfaceIndex);
}
case JAVASOCKOPT_SO_SNDBUF: {
result = getsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intValue, &intSize);
@@ -2963,7 +3172,10 @@
return newJavaLangBoolean(env, intValue);
}
case JAVASOCKOPT_IP_MULTICAST_LOOP: {
- result = getsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intValue, &intSize);
+ result = getOrSetSocketOption(SOCKOPT_GET, handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP, &intValue,
+ &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -2971,7 +3183,8 @@
return newJavaLangBoolean(env, intValue);
}
case JAVASOCKOPT_IP_TOS: {
- result = getsockopt(handle, IPPROTO_IP, IP_TOS, &intValue, &intSize);
+ result = getOrSetSocketOption(SOCKOPT_GET, handle, IP_TOS,
+ IPV6_TCLASS, &intValue, &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return NULL;
@@ -3001,9 +3214,11 @@
// LOGD("ENTER setSocketOptionImpl");
int handle, result;
- int intVal, intSize = sizeof(int);
- unsigned char byteVal, byteSize = sizeof(unsigned char);
- struct sockaddr_in sockVal;
+ int intVal;
+ socklen_t intSize = sizeof(int);
+ unsigned char byteVal;
+ socklen_t byteSize = sizeof(unsigned char);
+ struct sockaddr_storage sockVal;
int sockSize = sizeof(sockVal);
if (env->IsInstanceOf(optVal, gCachedFields.integer_class)) {
@@ -3014,7 +3229,7 @@
byteVal = (int) env->GetByteField(optVal, gCachedFields.byte_class_value);
} else if (env->IsInstanceOf(optVal, gCachedFields.iaddr_class)) {
if (inetAddressToSocketAddress(env, optVal, 0, &sockVal) < 0) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ // Exception has already been thrown.
return;
}
} else if (env->IsInstanceOf(optVal, gCachedFields.genericipmreq_class)) {
@@ -3026,7 +3241,7 @@
handle = jniGetFDFromFileDescriptor(env, fileDescriptor);
if (handle == 0 || handle == -1) {
- throwSocketException(env, SOCKERR_BADSOCKET);
+ throwSocketException(env, SOCKERR_BADDESC);
return;
}
@@ -3056,11 +3271,13 @@
break;
}
- case JAVASOCKOPT_MCAST_TTL: {
+ case JAVASOCKOPT_MCAST_TTL: {
if ((anOption >> 16) & BROKEN_MULTICAST_TTL) {
return;
}
- result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_TTL, &byteVal, byteSize);
+ result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS, &byteVal,
+ &byteSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3071,23 +3288,28 @@
case JAVASOCKOPT_MCAST_ADD_MEMBERSHIP: {
mcastAddDropMembership(env, handle, optVal,
(anOption >> 16) & BROKEN_MULTICAST_IF, IP_ADD_MEMBERSHIP);
- return;
+ break;
}
case JAVASOCKOPT_MCAST_DROP_MEMBERSHIP: {
mcastAddDropMembership(env, handle, optVal,
(anOption >> 16) & BROKEN_MULTICAST_IF, IP_DROP_MEMBERSHIP);
- return;
+ break;
}
case JAVASOCKOPT_MCAST_INTERFACE: {
if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
return;
}
+ // This call is IPv4 only.
+ if (getSocketAddressFamily(handle) != AF_INET) {
+ throwSocketException(env, SOCKERR_BADAF);
+ return;
+ }
struct ip_mreqn mcast_req;
memset(&mcast_req, 0, sizeof(mcast_req));
- memcpy(&(mcast_req.imr_address), &(sockVal.sin_addr),
- sizeof(struct in_addr));
+ struct sockaddr_in *sin = (struct sockaddr_in *) &sockVal;
+ mcast_req.imr_address = sin->sin_addr;
result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_IF,
&mcast_req, sizeof(mcast_req));
if (0 != result) {
@@ -3097,6 +3319,42 @@
break;
}
+ case JAVASOCKOPT_IP_MULTICAST_IF2: {
+ if ((anOption >> 16) & BROKEN_MULTICAST_IF) {
+ return;
+ }
+ int addressFamily = getSocketAddressFamily(handle);
+ int interfaceIndex = intVal;
+ void *optionValue;
+ socklen_t optionLength;
+ struct ip_mreqn multicastRequest;
+ switch (addressFamily) {
+ case AF_INET:
+ // IP_MULTICAST_IF expects a pointer to a struct ip_mreqn.
+ memset(&multicastRequest, 0, sizeof(multicastRequest));
+ multicastRequest.imr_ifindex = interfaceIndex;
+ optionValue = &multicastRequest;
+ optionLength = sizeof(multicastRequest);
+ break;
+ case AF_INET6:
+ // IPV6_MULTICAST_IF expects a pointer to an integer.
+ optionValue = &interfaceIndex;
+ optionLength = sizeof(interfaceIndex);
+ break;
+ default:
+ throwSocketException(env, SOCKERR_BADAF);
+ return;
+ }
+ result = getOrSetSocketOption(SOCKOPT_SET, handle,
+ IP_MULTICAST_IF, IPV6_MULTICAST_IF, optionValue,
+ &optionLength);
+ if (0 != result) {
+ throwSocketException(env, convertError(errno));
+ return;
+ }
+ break;
+ }
+
case JAVASOCKOPT_SO_SNDBUF: {
result = setsockopt(handle, SOL_SOCKET, SO_SNDBUF, &intVal, intSize);
if (0 != result) {
@@ -3151,7 +3409,10 @@
}
case JAVASOCKOPT_IP_MULTICAST_LOOP: {
- result = setsockopt(handle, IPPROTO_IP, IP_MULTICAST_LOOP, &intVal, intSize);
+ result = getOrSetSocketOption(SOCKOPT_SET, handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP, &intVal,
+ &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3160,7 +3421,8 @@
}
case JAVASOCKOPT_IP_TOS: {
- result = setsockopt(handle, IPPROTO_IP, IP_TOS, &intVal, intSize);
+ result = getOrSetSocketOption(SOCKOPT_SET, handle, IP_TOS,
+ IPV6_TCLASS, &intVal, &intSize);
if (0 != result) {
throwSocketException(env, convertError(errno));
return;
@@ -3215,8 +3477,6 @@
return;
}
- log_socket_close(handle, SOCKET_CLOSE_LOCAL);
-
jniSetFileDescriptorOfFD(env, fileDescriptor, -1);
close(handle);
@@ -3311,6 +3571,7 @@
env->SetObjectField(sender, gCachedFields.iaddr_ipaddress, address);
}
+// TODO: rewrite this method in Java and make it support IPv6.
static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) {
// LOGD("ENTER inheritedChannelImpl");
diff --git a/libcore/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java b/libcore/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java
index bb3f8f5..748105a 100644
--- a/libcore/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java
+++ b/libcore/luni/src/test/java/tests/api/java/io/InputStreamReaderTest.java
@@ -726,10 +726,12 @@
char[] chars = new char[8192];
int at = 0;
- outer:
for (;;) {
int amt = isr.read(chars);
- if (amt <= 0) break;
+ if (amt <= 0) {
+ break;
+ }
+
for (int i = 0; i < amt; i++) {
char c = chars[i];
if (at < prefixLength) {
diff --git a/libcore/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java b/libcore/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java
index b7a1012..ce34dba 100755
--- a/libcore/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java
+++ b/libcore/nio/src/test/java/org/apache/harmony/nio/tests/java/nio/channels/SocketChannelTest.java
@@ -29,6 +29,8 @@
import java.io.OutputStream;
import java.net.BindException;
import java.net.ConnectException;
+import java.net.Inet4Address;
+import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
@@ -4114,6 +4116,95 @@
}
}
+ /**
+ * @throws IOException
+ * @tests java.nio.channels.SocketChannel#read(ByteBuffer)
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "",
+ method = "read",
+ args = {java.nio.ByteBuffer[].class}
+ )
+ public void test_socketChannel_read_DirectByteBuffer() throws InterruptedException, IOException {
+
+ ServerThread server = new ServerThread();
+ server.start();
+ Thread.currentThread().sleep(1000);
+
+ InetSocketAddress address = new InetSocketAddress(InetAddress
+ .getByName("localhost"), port);
+
+ // First test with array based byte buffer
+ SocketChannel sc = SocketChannel.open();
+ sc.connect(address);
+
+ ByteBuffer buf = ByteBuffer.allocate(data.length);
+ buf.limit(data.length / 2);
+ sc.read(buf);
+
+ buf.limit(buf.capacity());
+ sc.read(buf);
+ sc.close();
+
+ // Make sure the buffer is filled correctly
+ buf.rewind();
+ assertSameContent(data, buf);
+
+ // Now test with direct byte buffer
+ sc = SocketChannel.open();
+ sc.connect(address);
+
+ buf = ByteBuffer.allocateDirect(data.length);
+ buf.limit(data.length / 2);
+ sc.read(buf);
+
+ buf.limit(buf.capacity());
+ sc.read(buf);
+ sc.close();
+
+ // Make sure the buffer is filled correctly
+ buf.rewind();
+ assertSameContent(data, buf);
+ }
+
+ private void assertSameContent(byte[] data, ByteBuffer buf) {
+ for (byte b : data) {
+ if (b != buf.get()) {
+ int pos = buf.position() - 1;
+ fail("Content not equal. Buffer position: " +
+ (pos) + " expected: " + b + " was: " + buf.get(pos));
+ }
+ }
+ }
+
+ public static boolean done = false;
+ public static int port = Support_PortManager.getNextPort();
+ public static byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ static class ServerThread extends Thread {
+ @Override
+ public void run() {
+ try {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ InetSocketAddress addr = new InetSocketAddress(InetAddress
+ .getByAddress(new byte[] {0, 0, 0, 0}), port);
+ ssc.socket().bind(addr, 0);
+
+ ByteBuffer buf = ByteBuffer.allocate(10);
+ buf.put(data);
+
+ while (!done) {
+ SocketChannel sc = ssc.accept();
+ buf.rewind();
+ sc.write(buf);
+ }
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
class MockSocketChannel extends SocketChannel {
private boolean isWriteCalled = false;
diff --git a/libcore/prefs/src/main/java/java/util/prefs/Preferences.java b/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
index b7a0c70..719c89a 100644
--- a/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
+++ b/libcore/prefs/src/main/java/java/util/prefs/Preferences.java
@@ -1006,15 +1006,11 @@
//parse node's absolute path from class instance
private static String getNodeName(Class<?> c){
- // ??? PREFS TODO change back to harmony code once getPackage
- // delivers the correct results
- // Package p = c.getPackage();
- // if(null == p){
- // return "/<unnamed>"; //$NON-NLS-1$
- // }
- // return "/"+p.getName().replace('.', '/'); //$NON-NLS-1$
- int dotIndex = c.getName().lastIndexOf(".");
- return "/" + c.getName().substring(0, dotIndex).replace(".", "/");
+ Package p = c.getPackage();
+ if(null == p){
+ return "/<unnamed>"; //$NON-NLS-1$
+ }
+ return "/"+p.getName().replace('.', '/'); //$NON-NLS-1$
}
/**
diff --git a/libcore/text/src/main/java/java/text/RuleBasedCollator.java b/libcore/text/src/main/java/java/text/RuleBasedCollator.java
index 41a51e2..6418962 100644
--- a/libcore/text/src/main/java/java/text/RuleBasedCollator.java
+++ b/libcore/text/src/main/java/java/text/RuleBasedCollator.java
@@ -390,7 +390,7 @@
/**
* Returns the collation rules of this collator. These {@code rules} can be
- * fed into the {@link #RuleBasedCollator(String)} constructor.
+ * fed into the {@code RuleBasedCollator(String)} constructor.
* <p>
* Note that the {@code rules} are actually interpreted as a delta to the
* standard Unicode Collation Algorithm (UCA). Hence, an empty {@code rules}
diff --git a/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp b/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
index 250cf83..fd68460 100644
--- a/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
+++ b/libcore/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp
@@ -36,8 +36,6 @@
#include <openssl/rand.h>
#include <openssl/ssl.h>
-#include <utils/LogSocket.h>
-
#include "org_apache_harmony_xnet_provider_jsse_common.h"
/**
@@ -693,7 +691,6 @@
switch (error) {
// Sucessfully read at least one byte.
case SSL_ERROR_NONE: {
- add_recv_stats(fd, result);
return result;
}
@@ -861,7 +858,6 @@
}
}
}
- add_send_stats(fd, count);
// LOGD("Successfully wrote %d bytes", count);
return count;
diff --git a/libdex/DexFile.c b/libdex/DexFile.c
index 2639d7b..99b38c9 100644
--- a/libdex/DexFile.c
+++ b/libdex/DexFile.c
@@ -13,12 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Access the contents of a .dex file.
*/
#include "DexFile.h"
#include "DexProto.h"
+#include "DexCatch.h"
#include "Leb128.h"
#include "sha1.h"
#include "ZipArchive.h"
@@ -643,6 +645,10 @@
}
indexMapType = *pAux;
break;
+ case kDexChunkRegisterMaps:
+ LOGV("+++ found register maps, size=%u\n", size);
+ pDexFile->pRegisterMapPool = data;
+ break;
default:
LOGI("Unknown chunk 0x%08x (%c%c%c%c), size=%d in aux data area\n",
*pAux,
@@ -883,6 +889,43 @@
/*
+ * Compute the size, in bytes, of a DexCode.
+ */
+size_t dexGetDexCodeSize(const DexCode* pCode)
+{
+ /*
+ * The catch handler data is the last entry. It has a variable number
+ * of variable-size pieces, so we need to create an iterator.
+ */
+ u4 handlersSize;
+ u4 offset;
+ u4 ui;
+
+ if (pCode->triesSize != 0) {
+ handlersSize = dexGetHandlersSize(pCode);
+ offset = dexGetFirstHandlerOffset(pCode);
+ } else {
+ handlersSize = 0;
+ offset = 0;
+ }
+
+ for (ui = 0; ui < handlersSize; ui++) {
+ DexCatchIterator iterator;
+ dexCatchIteratorInit(&iterator, pCode, offset);
+ offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
+ }
+
+ const u1* handlerData = dexGetCatchHandlerData(pCode);
+
+ //LOGD("+++ pCode=%p handlerData=%p last offset=%d\n",
+ // pCode, handlerData, offset);
+
+ /* return the size of the catch handler + everything before it */
+ return (handlerData - (u1*) pCode) + offset;
+}
+
+
+/*
* ===========================================================================
* Debug info
* ===========================================================================
@@ -1181,3 +1224,4 @@
free(methodDescriptor);
}
}
+
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index d1ea5eb..4b5fe7c 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -163,6 +163,7 @@
/* auxillary data section chunk codes */
enum {
kDexChunkClassLookup = 0x434c4b50, /* CLKP */
+ kDexChunkRegisterMaps = 0x524d4150, /* RMAP */
kDexChunkReducingIndexMap = 0x5249584d, /* RIXM */
kDexChunkExpandingIndexMap = 0x4549584d, /* EIXM */
@@ -514,11 +515,13 @@
const DexClassDef* pClassDefs;
const DexLink* pLinkData;
- /* mapped in "auxillary" section */
+ /*
+ * These are mapped out of the "auxillary" section, and may not be
+ * included in the file.
+ */
const DexClassLookup* pClassLookup;
-
- /* mapped in "auxillary" section */
DexIndexMap indexMap;
+ const void* pRegisterMapPool; // RegisterMapClassPool
/* points to start of DEX file data */
const u1* baseAddr;
@@ -672,6 +675,15 @@
return &pDexFile->pClassDefs[idx];
}
+/* given a ClassDef pointer, recover its index */
+DEX_INLINE u4 dexGetIndexForClassDef(const DexFile* pDexFile,
+ const DexClassDef* pClassDef)
+{
+ assert(pClassDef >= pDexFile->pClassDefs &&
+ pClassDef < pDexFile->pClassDefs + pDexFile->pHeader->classDefsSize);
+ return pClassDef - pDexFile->pClassDefs;
+}
+
/* get the interface list for a DexClass */
DEX_INLINE const DexTypeList* dexGetInterfacesList(const DexFile* pDexFile,
const DexClassDef* pClassDef)
@@ -723,6 +735,9 @@
return dexStringById(pDexFile, pClassDef->sourceFileIdx);
}
+/* get the size, in bytes, of a DexCode */
+size_t dexGetDexCodeSize(const DexCode* pCode);
+
/* Get the list of "tries" for the given DexCode. */
DEX_INLINE const DexTry* dexGetTries(const DexCode* pCode) {
const u2* insnsEnd = &pCode->insns[pCode->insnsSize];
@@ -741,6 +756,7 @@
return (const u1*) &pTries[pCode->triesSize];
}
+/* get a pointer to the start of the debugging data */
DEX_INLINE const u1* dexGetDebugInfoStream(const DexFile* pDexFile,
const DexCode* pCode)
{
diff --git a/libdex/DexSwapVerify.c b/libdex/DexSwapVerify.c
index 5ecda9f..bc6f51f 100644
--- a/libdex/DexSwapVerify.c
+++ b/libdex/DexSwapVerify.c
@@ -362,12 +362,15 @@
static bool swapMap(CheckState* state, DexMapList* pMap)
{
DexMapItem* item = pMap->list;
- u4 count = pMap->size;
+ u4 count;
u4 dataItemCount = 0; // Total count of items in the data section.
u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
u4 usedBits = 0; // Bit set: one bit per section
bool first = true;
u4 lastOffset = 0;
+
+ SWAP_FIELD4(pMap->size);
+ count = pMap->size;
CHECK_LIST_SIZE(item, count, sizeof(DexMapItem));
@@ -392,21 +395,21 @@
}
if (isDataSectionType(item->type)) {
- u4 count = item->size;
+ u4 icount = item->size;
/*
* This sanity check on the data section items ensures that
* there are no more items than the number of bytes in
* the data section.
*/
- if (count > dataItemsLeft) {
+ if (icount > dataItemsLeft) {
LOGE("Unrealistically many items in the data section: "
- "at least %d\n", dataItemCount + count);
+ "at least %d\n", dataItemCount + icount);
return false;
}
- dataItemsLeft -= count;
- dataItemCount += count;
+ dataItemsLeft -= icount;
+ dataItemCount += icount;
}
u4 bit = mapTypeToBitMask(item->type);
@@ -2077,6 +2080,7 @@
while (size--) {
data = verifyEncodedValue(state, data, crossVerify);
if (data == NULL) {
+ LOGE("Bogus encoded_array value\n");
return NULL;
}
}
diff --git a/libdex/InstrUtils.c b/libdex/InstrUtils.c
index b0718f3..b58e647 100644
--- a/libdex/InstrUtils.c
+++ b/libdex/InstrUtils.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Dalvik instruction utility functions.
*/
@@ -49,7 +50,7 @@
int width = 0;
switch (opc) {
- case OP_NOP: /* switch-statement data is a special case of NOP */
+ case OP_NOP: /* note data for e.g. switch-* encoded "inside" a NOP */
case OP_MOVE:
case OP_MOVE_WIDE:
case OP_MOVE_OBJECT:
@@ -289,6 +290,7 @@
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
+ case OP_THROW_VERIFICATION_ERROR:
width = -2;
break;
case OP_INVOKE_VIRTUAL_QUICK:
@@ -320,7 +322,6 @@
case OP_UNUSED_EA:
case OP_UNUSED_EB:
case OP_UNUSED_EC:
- case OP_UNUSED_ED:
case OP_UNUSED_EF:
case OP_UNUSED_F1:
case OP_UNUSED_FC:
@@ -538,16 +539,6 @@
case OP_SPUT_SHORT:
case OP_SPUT_WIDE:
case OP_SPUT_OBJECT:
- case OP_INVOKE_VIRTUAL:
- case OP_INVOKE_VIRTUAL_RANGE:
- case OP_INVOKE_SUPER:
- case OP_INVOKE_SUPER_RANGE:
- case OP_INVOKE_DIRECT:
- case OP_INVOKE_DIRECT_RANGE:
- case OP_INVOKE_STATIC:
- case OP_INVOKE_STATIC_RANGE:
- case OP_INVOKE_INTERFACE:
- case OP_INVOKE_INTERFACE_RANGE:
case OP_DIV_INT:
case OP_REM_INT:
case OP_DIV_LONG:
@@ -563,6 +554,19 @@
flags = kInstrCanContinue | kInstrCanThrow;
break;
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ flags = kInstrCanContinue | kInstrCanThrow | kInstrInvoke;
+ break;
+
case OP_RETURN_VOID:
case OP_RETURN:
case OP_RETURN_WIDE:
@@ -578,7 +582,7 @@
case OP_GOTO:
case OP_GOTO_16:
case OP_GOTO_32:
- flags = kInstrCanBranch;
+ flags = kInstrCanBranch | kInstrUnconditional;
break;
/* conditional branches */
@@ -603,7 +607,10 @@
flags = kInstrCanSwitch | kInstrCanContinue;
break;
- /* optimizer-generated instructions */
+ /* verifier/optimizer-generated instructions */
+ case OP_THROW_VERIFICATION_ERROR:
+ flags = kInstrCanThrow;
+ break;
case OP_EXECUTE_INLINE:
flags = kInstrCanContinue;
break;
@@ -613,12 +620,15 @@
case OP_IPUT_QUICK:
case OP_IPUT_WIDE_QUICK:
case OP_IPUT_OBJECT_QUICK:
+ flags = kInstrCanContinue | kInstrCanThrow;
+ break;
+
case OP_INVOKE_VIRTUAL_QUICK:
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE:
case OP_INVOKE_DIRECT_EMPTY:
- flags = kInstrCanContinue | kInstrCanThrow;
+ flags = kInstrCanContinue | kInstrCanThrow | kInstrInvoke;
break;
/* these should never appear */
@@ -641,13 +651,13 @@
case OP_UNUSED_EA:
case OP_UNUSED_EB:
case OP_UNUSED_EC:
- case OP_UNUSED_ED:
case OP_UNUSED_EF:
case OP_UNUSED_F1:
case OP_UNUSED_FC:
case OP_UNUSED_FD:
case OP_UNUSED_FE:
case OP_UNUSED_FF:
+ flags = kInstrNoJit;
break;
/*
@@ -950,6 +960,9 @@
/*
* Optimized instructions.
*/
+ case OP_THROW_VERIFICATION_ERROR:
+ fmt = kFmt20bc;
+ break;
case OP_IGET_QUICK:
case OP_IGET_WIDE_QUICK:
case OP_IGET_OBJECT_QUICK:
@@ -993,7 +1006,6 @@
case OP_UNUSED_EA:
case OP_UNUSED_EB:
case OP_UNUSED_EC:
- case OP_UNUSED_ED:
case OP_UNUSED_EF:
case OP_UNUSED_F1:
case OP_UNUSED_FC:
@@ -1038,38 +1050,39 @@
pDec->opCode = (OpCode) INST_INST(inst);
switch (dexGetInstrFormat(fmts, pDec->opCode)) {
- case kFmt10x: // op
+ case kFmt10x: // op
/* nothing to do; copy the AA bits out for the verifier */
pDec->vA = INST_AA(inst);
break;
- case kFmt12x: // op vA, vB
+ case kFmt12x: // op vA, vB
pDec->vA = INST_A(inst);
pDec->vB = INST_B(inst);
break;
- case kFmt11n: // op vA, #+B
+ case kFmt11n: // op vA, #+B
pDec->vA = INST_A(inst);
pDec->vB = (s4) (INST_B(inst) << 28) >> 28; // sign extend 4-bit value
break;
- case kFmt11x: // op vAA
+ case kFmt11x: // op vAA
pDec->vA = INST_AA(inst);
break;
- case kFmt10t: // op +AA
+ case kFmt10t: // op +AA
pDec->vA = (s1) INST_AA(inst); // sign-extend 8-bit value
break;
- case kFmt20t: // op +AAAA
+ case kFmt20t: // op +AAAA
pDec->vA = (s2) FETCH(1); // sign-extend 16-bit value
break;
- case kFmt21c: // op vAA, thing@BBBB
- case kFmt22x: // op vAA, vBBBB
+ case kFmt20bc: // op AA, thing@BBBB
+ case kFmt21c: // op vAA, thing@BBBB
+ case kFmt22x: // op vAA, vBBBB
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1);
break;
- case kFmt21s: // op vAA, #+BBBB
- case kFmt21t: // op vAA, +BBBB
+ case kFmt21s: // op vAA, #+BBBB
+ case kFmt21t: // op vAA, +BBBB
pDec->vA = INST_AA(inst);
pDec->vB = (s2) FETCH(1); // sign-extend 16-bit value
break;
- case kFmt21h: // op vAA, #+BBBB0000[00000000]
+ case kFmt21h: // op vAA, #+BBBB0000[00000000]
pDec->vA = INST_AA(inst);
/*
* The value should be treated as right-zero-extended, but we don't
@@ -1078,24 +1091,24 @@
*/
pDec->vB = FETCH(1);
break;
- case kFmt23x: // op vAA, vBB, vCC
+ case kFmt23x: // op vAA, vBB, vCC
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1) & 0xff;
pDec->vC = FETCH(1) >> 8;
break;
- case kFmt22b: // op vAA, vBB, #+CC
+ case kFmt22b: // op vAA, vBB, #+CC
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1) & 0xff;
pDec->vC = (s1) (FETCH(1) >> 8); // sign-extend 8-bit value
break;
- case kFmt22s: // op vA, vB, #+CCCC
- case kFmt22t: // op vA, vB, +CCCC
+ case kFmt22s: // op vA, vB, #+CCCC
+ case kFmt22t: // op vA, vB, +CCCC
pDec->vA = INST_A(inst);
pDec->vB = INST_B(inst);
pDec->vC = (s2) FETCH(1); // sign-extend 16-bit value
break;
- case kFmt22c: // op vA, vB, thing@CCCC
- case kFmt22cs: // [opt] op vA, vB, field offset CCCC
+ case kFmt22c: // op vA, vB, thing@CCCC
+ case kFmt22cs: // [opt] op vA, vB, field offset CCCC
pDec->vA = INST_A(inst);
pDec->vB = INST_B(inst);
pDec->vC = FETCH(1);
@@ -1103,21 +1116,21 @@
case kFmt30t: // op +AAAAAAAA
pDec->vA = FETCH(1) | ((u4) FETCH(2) << 16); // signed 32-bit value
break;
- case kFmt31t: // op vAA, +BBBBBBBB
- case kFmt31c: // op vAA, thing@BBBBBBBB
+ case kFmt31t: // op vAA, +BBBBBBBB
+ case kFmt31c: // op vAA, thing@BBBBBBBB
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1) | ((u4) FETCH(2) << 16); // 32-bit value
break;
- case kFmt32x: // op vAAAA, vBBBB
+ case kFmt32x: // op vAAAA, vBBBB
pDec->vA = FETCH(1);
pDec->vB = FETCH(2);
break;
- case kFmt31i: // op vAA, #+BBBBBBBB
+ case kFmt31i: // op vAA, #+BBBBBBBB
pDec->vA = INST_AA(inst);
pDec->vB = FETCH(1) | ((u4) FETCH(2) << 16);
break;
- case kFmt35c: // op vB, {vD..vG,vA}, thing@CCCC
- case kFmt35ms: // [opt] invoke-virtual+super
+ case kFmt35c: // op vB, {vD..vG,vA}, thing@CCCC
+ case kFmt35ms: // [opt] invoke-virtual+super
{
/*
* The lettering changes that came about when we went from 4 args
@@ -1158,7 +1171,7 @@
pDec->vC = pDec->arg[0];
}
break;
- case kFmt3inline: // [opt] inline invoke
+ case kFmt3inline: // [opt] inline invoke
{
u2 regList;
int i;
diff --git a/libdex/InstrUtils.h b/libdex/InstrUtils.h
index 9d8e5c3..5ca175e 100644
--- a/libdex/InstrUtils.h
+++ b/libdex/InstrUtils.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Dalvik instruction utility functions.
*/
@@ -42,6 +43,7 @@
kFmt11n, // op vA, #+B
kFmt11x, // op vAA
kFmt10t, // op +AA
+ kFmt20bc, // op AA, thing@BBBB
kFmt20t, // op +AAAA
kFmt22x, // op vAA, vBBBB
kFmt21t, // op vAA, +BBBB
@@ -97,6 +99,9 @@
kInstrCanSwitch = 1 << 2, // switch statement
kInstrCanThrow = 1 << 3, // could cause an exception to be thrown
kInstrCanReturn = 1 << 4, // returns, no additional statements
+ kInstrInvoke = 1 << 5, // a flavor of invoke
+ kInstrUnconditional = 1 << 6, // unconditional branch
+ kInstrNoJit = 1 << 7, // don't jit trace containing this
};
diff --git a/libdex/Leb128.h b/libdex/Leb128.h
index 215ae30..41799fe 100644
--- a/libdex/Leb128.h
+++ b/libdex/Leb128.h
@@ -124,4 +124,41 @@
*/
int readAndVerifySignedLeb128(const u1** pStream, const u1* limit, bool* okay);
+
+/*
+ * Writes a 32-bit value in unsigned ULEB128 format.
+ *
+ * Returns the updated pointer.
+ */
+DEX_INLINE u1* writeUnsignedLeb128(u1* ptr, u4 data)
+{
+ while (true) {
+ u1 out = data & 0x7f;
+ if (out != data) {
+ *ptr++ = out | 0x80;
+ data >>= 7;
+ } else {
+ *ptr++ = out;
+ break;
+ }
+ }
+
+ return ptr;
+}
+
+/*
+ * Returns the number of bytes needed to encode "val" in ULEB128 form.
+ */
+DEX_INLINE int unsignedLeb128Size(u4 data)
+{
+ int count = 0;
+
+ do {
+ data >>= 7;
+ count++;
+ } while (data != 0);
+
+ return count;
+}
+
#endif
diff --git a/libdex/OpCode.h b/libdex/OpCode.h
index d389472..1272231 100644
--- a/libdex/OpCode.h
+++ b/libdex/OpCode.h
@@ -331,9 +331,9 @@
OP_UNUSED_EA = 0xea,
OP_UNUSED_EB = 0xeb,
OP_UNUSED_EC = 0xec,
- OP_UNUSED_ED = 0xed,
/* optimizer output -- these are never generated by "dx" */
+ OP_THROW_VERIFICATION_ERROR = 0xed,
OP_EXECUTE_INLINE = 0xee,
OP_UNUSED_EF = 0xef, /* OP_EXECUTE_INLINE_RANGE? */
@@ -628,7 +628,7 @@
H(OP_UNUSED_EA), \
H(OP_UNUSED_EB), \
H(OP_UNUSED_EC), \
- H(OP_UNUSED_ED), \
+ H(OP_THROW_VERIFICATION_ERROR), \
H(OP_EXECUTE_INLINE), \
H(OP_UNUSED_EF), \
/* f0..ff */ \
diff --git a/libdex/SysUtil.c b/libdex/SysUtil.c
index 530ac2e..bf1be88 100644
--- a/libdex/SysUtil.c
+++ b/libdex/SysUtil.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* System utilities.
*/
@@ -64,6 +65,25 @@
#endif
}
+/*
+ * Create a private anonymous storage area.
+ */
+int sysCreatePrivateMap(size_t length, MemMapping* pMap)
+{
+ void* memPtr;
+
+ memPtr = sysCreateAnonShmem(length);
+ if (memPtr == NULL)
+ return -1;
+
+ pMap->addr = pMap->baseAddr = memPtr;
+ pMap->length = pMap->baseLength = length;
+ return 0;
+}
+
+/*
+ * Determine the current offset and remaining length of the open file.
+ */
static int getFileStartAndLength(int fd, off_t *start_, size_t *length_)
{
off_t start, end;
diff --git a/libdex/SysUtil.h b/libdex/SysUtil.h
index 8d85efa..8b80503 100644
--- a/libdex/SysUtil.h
+++ b/libdex/SysUtil.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* System utilities.
*/
@@ -63,6 +64,13 @@
MemMapping* pMap);
/*
+ * Create a private anonymous mapping, useful for large allocations.
+ *
+ * On success, "pMap" is filled in, and zero is returned.
+ */
+int sysCreatePrivateMap(size_t length, MemMapping* pMap);
+
+/*
* Release the pages associated with a shared memory segment.
*
* This does not free "pMap"; it just releases the memory.
diff --git a/libdex/ZipArchive.c b/libdex/ZipArchive.c
index a75a85b..3f88e7d 100644
--- a/libdex/ZipArchive.c
+++ b/libdex/ZipArchive.c
@@ -285,6 +285,8 @@
LOGV("Opening archive '%s' %p\n", fileName, pArchive);
+ memset(pArchive, 0, sizeof(ZipArchive));
+
fd = open(fileName, O_RDONLY, 0);
if (fd < 0) {
err = errno ? errno : -1;
diff --git a/libnativehelper/include/nativehelper/JNIHelp.h b/libnativehelper/include/nativehelper/JNIHelp.h
index eec7af8..3982797 100644
--- a/libnativehelper/include/nativehelper/JNIHelp.h
+++ b/libnativehelper/include/nativehelper/JNIHelp.h
@@ -42,6 +42,8 @@
/*
* Throw an exception with the specified class and an optional message.
+ * The "className" argument will be passed directly to FindClass, which
+ * takes strings with slashes (e.g. "java/lang/Object").
*
* Returns 0 on success, nonzero if something failed (e.g. the exception
* class couldn't be found).
diff --git a/tests/003-omnibus-opcodes/expected.txt b/tests/003-omnibus-opcodes/expected.txt
index 81a8879..4895dc3 100644
--- a/tests/003-omnibus-opcodes/expected.txt
+++ b/tests/003-omnibus-opcodes/expected.txt
@@ -23,6 +23,7 @@
IntMath.divideByZero
IntMath.bigDivideOverflow
IntMath.checkConsts
+IntMath.jlmTests
FloatMath.convTest
FloatMath.floatOperTest
FloatMath.doubleOperTest
@@ -39,6 +40,7 @@
2: 123.45600128173828
-2.005440939E9, -8.6133032459203287E18, 123.4560012817382
FloatMath.checkConsts
+FloatMath.jlmTests
IntMath.testIntCompare
IntMath.testLongCompare
IntMath.testFloatCompare
@@ -64,8 +66,9 @@
Throw.twoA
Throw.twoN
Throw.rethrow
-Caught: java.lang.VerifyError: UnresTest1
-Caught (retry): java.lang.VerifyError: UnresTest1
-Caught: java.lang.VerifyError: UnresTest2
+UnresTest1...
+UnresTest1...
+UnresTest2...
+UnresTest2 done
InternedString.run
Done!
diff --git a/tests/003-omnibus-opcodes/src/FloatMath.java b/tests/003-omnibus-opcodes/src/FloatMath.java
index 0c1fe1b..cf4869c 100644
--- a/tests/003-omnibus-opcodes/src/FloatMath.java
+++ b/tests/003-omnibus-opcodes/src/FloatMath.java
@@ -262,6 +262,50 @@
assert(d > 9.9 && d < 10.1);
}
+ /*
+ * Determine if two floating point numbers are approximately equal.
+ *
+ * (Assumes that floating point is generally working, so we can't use
+ * this for the first set of tests.)
+ */
+ static boolean approxEqual(float a, float b, float maxDelta) {
+ if (a > b)
+ return (a - b) < maxDelta;
+ else
+ return (b - a) < maxDelta;
+ }
+ static boolean approxEqual(double a, double b, double maxDelta) {
+ if (a > b)
+ return (a - b) < maxDelta;
+ else
+ return (b - a) < maxDelta;
+ }
+
+ /*
+ * Test some java.lang.Math functions.
+ *
+ * The method arguments are positive values.
+ */
+ static void jlmTests(float ff, double dd) {
+ System.out.println("FloatMath.jlmTests");
+
+ assert(approxEqual(Math.abs(ff), ff, 0.001f));
+ assert(approxEqual(Math.abs(-ff), ff, 0.001f));
+ assert(approxEqual(Math.min(ff, -5.0f), -5.0f, 0.001f));
+ assert(approxEqual(Math.max(ff, -5.0f), ff, 0.001f));
+
+ assert(approxEqual(Math.abs(dd), dd, 0.001));
+ assert(approxEqual(Math.abs(-dd), dd, 0.001));
+ assert(approxEqual(Math.min(dd, -5.0), -5.0, 0.001));
+ assert(approxEqual(Math.max(dd, -5.0), dd, 0.001));
+
+ double sq = Math.sqrt(dd);
+ assert(approxEqual(sq*sq, dd, 0.001));
+
+ assert(approxEqual(0.5403023058681398, Math.cos(1.0), 0.00000001));
+ assert(approxEqual(0.8414709848078965, Math.sin(1.0), 0.00000001));
+ }
+
public static void run() {
convTest();
@@ -287,6 +331,8 @@
unopTest(123.456f);
checkConsts();
+
+ jlmTests(3.14159f, 123456.78987654321);
}
}
diff --git a/tests/003-omnibus-opcodes/src/IntMath.java b/tests/003-omnibus-opcodes/src/IntMath.java
index 126bec6..d5ac744 100644
--- a/tests/003-omnibus-opcodes/src/IntMath.java
+++ b/tests/003-omnibus-opcodes/src/IntMath.java
@@ -432,6 +432,25 @@
assert(huge == 0x9922334455667788L); // const-wide
}
+ /*
+ * Test some java.lang.Math functions.
+ *
+ * The method arguments are positive values.
+ */
+ static void jlmTests(int ii, long ll) {
+ System.out.println("IntMath.jlmTests");
+
+ assert(Math.abs(ii) == ii);
+ assert(Math.abs(-ii) == ii);
+ assert(Math.min(ii, -5) == -5);
+ assert(Math.max(ii, -5) == ii);
+
+ assert(Math.abs(ll) == ll);
+ assert(Math.abs(-ll) == ll);
+ assert(Math.min(ll, -5L) == -5L);
+ assert(Math.max(ll, -5L) == ll);
+ }
+
public static void run() {
shiftTest1();
shiftTest2();
@@ -467,6 +486,8 @@
checkConsts((byte) 1, (short) -256, -88888, 0x9922334455667788L);
unopCheck(unopTest(38));
+
+ jlmTests(12345, 0x1122334455667788L);
}
}
diff --git a/tests/003-omnibus-opcodes/src/UnresTest2.java b/tests/003-omnibus-opcodes/src/UnresTest2.java
index 43a92ac..b458bfe 100644
--- a/tests/003-omnibus-opcodes/src/UnresTest2.java
+++ b/tests/003-omnibus-opcodes/src/UnresTest2.java
@@ -44,6 +44,7 @@
}
checkCasts(stuff);
+ System.out.println("UnresTest2 done");
}
}
diff --git a/tests/042-new-instance/src/Main.java b/tests/042-new-instance/src/Main.java
index 49894fe..037aa2a 100644
--- a/tests/042-new-instance/src/Main.java
+++ b/tests/042-new-instance/src/Main.java
@@ -1,4 +1,20 @@
-// Copyright 2007 The Android Open Source Project
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Constructor;
import java.lang.reflect.Constructor;
@@ -29,7 +45,7 @@
try {
Class c = Class.forName("otherpackage.PackageAccess");
Object obj = c.newInstance();
- System.out.println("ERROR: PackageAccess succeeded unexpectedly");
+ System.err.println("ERROR: PackageAccess succeeded unexpectedly");
} catch (IllegalAccessException iae) {
System.out.println("Got expected PackageAccess complaint");
} catch (Exception ex) {
diff --git a/tests/046-reflect/expected.txt b/tests/046-reflect/expected.txt
index eefa448..3be8d1c 100644
--- a/tests/046-reflect/expected.txt
+++ b/tests/046-reflect/expected.txt
@@ -92,3 +92,6 @@
ReflectTest done!
checkType invoking null
checkType got expected exception
+got methods
+NoisyInitUser is initializing
+NoisyInit is initializing
diff --git a/tests/046-reflect/src/Main.java b/tests/046-reflect/src/Main.java
index 1ec63d8..99b1c4e 100644
--- a/tests/046-reflect/src/Main.java
+++ b/tests/046-reflect/src/Main.java
@@ -332,11 +332,23 @@
}
}
+ public static void checkInit() {
+ Class niuClass = NoisyInitUser.class;
+ Method[] methods;
+
+ methods = niuClass.getDeclaredMethods();
+ System.out.println("got methods");
+ /* neither NoisyInit nor NoisyInitUser should be initialized yet */
+ NoisyInitUser niu = new NoisyInitUser();
+ NoisyInit ni = new NoisyInit();
+ }
+
public static void main(String[] args) {
Main test = new Main();
test.run();
checkType();
+ checkInit();
}
}
@@ -407,3 +419,18 @@
public static double staticDouble = 3.3;
}
+class NoisyInit {
+ static {
+ System.out.println("NoisyInit is initializing");
+ //Throwable th = new Throwable();
+ //th.printStackTrace();
+ }
+}
+
+class NoisyInitUser {
+ static {
+ System.out.println("NoisyInitUser is initializing");
+ }
+ public void createNoisyInit(NoisyInit ni) {}
+}
+
diff --git a/tests/065-mismatched-implements/expected.txt b/tests/065-mismatched-implements/expected.txt
index 36ebe5e..09c0596 100644
--- a/tests/065-mismatched-implements/expected.txt
+++ b/tests/065-mismatched-implements/expected.txt
@@ -1,3 +1 @@
-Dalvik VM unable to find static main(String[]) in 'Main'
-java.lang.VerifyError: Main
- at dalvik.system.NativeStart.main(Native Method)
+Got expected ICCE
diff --git a/tests/065-mismatched-implements/info.txt b/tests/065-mismatched-implements/info.txt
index 58d9b69..74c3ff3 100644
--- a/tests/065-mismatched-implements/info.txt
+++ b/tests/065-mismatched-implements/info.txt
@@ -1,19 +1,2 @@
This tests what happens when class A implements interface B, but somebody
turns B into an abstract class without rebuilding A.
-
-If you run this with --no-verify you get reasonable results:
-
-java.lang.NoClassDefFoundError: Base
- at Main.main(Main.java:8)
- at dalvik.system.NativeStart.main(Native Method)
-Caused by: java.lang.IncompatibleClassChangeError: Base
- at dalvik.system.DexFile.defineClass(Native Method)
- at dalvik.system.DexFile.loadClass(DexFile.java:91)
- at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:175)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:453)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:421)
- ... 2 more
-
-With the verifier enabled, you get a relatively content-free VerifyError
-with the detail only appearing in the log file.
-
diff --git a/tests/065-mismatched-implements/src/Indirect.java b/tests/065-mismatched-implements/src/Indirect.java
new file mode 100644
index 0000000..dd87a65
--- /dev/null
+++ b/tests/065-mismatched-implements/src/Indirect.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+/**
+ * Error indirection class.
+ *
+ * Some VMs will load this class and fail on the "new" call, others will
+ * refuse to load this class at all.
+ */
+public class Indirect {
+ public static void main() {
+ Base base = new Base();
+ }
+}
+
diff --git a/tests/065-mismatched-implements/src/Main.java b/tests/065-mismatched-implements/src/Main.java
index 4a25232..6993b17 100644
--- a/tests/065-mismatched-implements/src/Main.java
+++ b/tests/065-mismatched-implements/src/Main.java
@@ -1,11 +1,30 @@
-// Copyright 2008 The Android Open Source Project
+/*
+ * 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.
+ */
/*
* Test field access through reflection.
*/
public class Main {
public static void main(String[] args) {
- Base base = new Base();
+ try {
+ Indirect.main();
+ System.err.println("Succeeded unexpectedly");
+ } catch (IncompatibleClassChangeError icce) {
+ System.out.println("Got expected ICCE");
+ }
}
}
diff --git a/tests/066-mismatched-super/expected.txt b/tests/066-mismatched-super/expected.txt
index 36ebe5e..09c0596 100644
--- a/tests/066-mismatched-super/expected.txt
+++ b/tests/066-mismatched-super/expected.txt
@@ -1,3 +1 @@
-Dalvik VM unable to find static main(String[]) in 'Main'
-java.lang.VerifyError: Main
- at dalvik.system.NativeStart.main(Native Method)
+Got expected ICCE
diff --git a/tests/066-mismatched-super/info.txt b/tests/066-mismatched-super/info.txt
index 2158899..7865ffc 100644
--- a/tests/066-mismatched-super/info.txt
+++ b/tests/066-mismatched-super/info.txt
@@ -1,19 +1,2 @@
This tests what happens when class A extends abstract class B, but somebody
turns B into an interface without rebuilding A.
-
-If you run this with --no-verify you get reasonable results:
-
-java.lang.NoClassDefFoundError: Base
- at Main.main(Main.java:8)
- at dalvik.system.NativeStart.main(Native Method)
-Caused by: java.lang.IncompatibleClassChangeError: superclass is an interface
- at dalvik.system.DexFile.defineClass(Native Method)
- at dalvik.system.DexFile.loadClass(DexFile.java:91)
- at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:175)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:453)
- at java.lang.ClassLoader.loadClass(ClassLoader.java:421)
- ... 2 more
-
-With the verifier enabled, you get a relatively content-free VerifyError
-with the detail only appearing in the log file.
-
diff --git a/tests/066-mismatched-super/src/Indirect.java b/tests/066-mismatched-super/src/Indirect.java
new file mode 100644
index 0000000..dd87a65
--- /dev/null
+++ b/tests/066-mismatched-super/src/Indirect.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+/**
+ * Error indirection class.
+ *
+ * Some VMs will load this class and fail on the "new" call, others will
+ * refuse to load this class at all.
+ */
+public class Indirect {
+ public static void main() {
+ Base base = new Base();
+ }
+}
+
diff --git a/tests/066-mismatched-super/src/Main.java b/tests/066-mismatched-super/src/Main.java
index 4a25232..6993b17 100644
--- a/tests/066-mismatched-super/src/Main.java
+++ b/tests/066-mismatched-super/src/Main.java
@@ -1,11 +1,30 @@
-// Copyright 2008 The Android Open Source Project
+/*
+ * 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.
+ */
/*
* Test field access through reflection.
*/
public class Main {
public static void main(String[] args) {
- Base base = new Base();
+ try {
+ Indirect.main();
+ System.err.println("Succeeded unexpectedly");
+ } catch (IncompatibleClassChangeError icce) {
+ System.out.println("Got expected ICCE");
+ }
}
}
diff --git a/tests/068-classloader/expected.txt b/tests/068-classloader/expected.txt
index 0ca8862..bf131ee 100644
--- a/tests/068-classloader/expected.txt
+++ b/tests/068-classloader/expected.txt
@@ -4,6 +4,9 @@
Got expected CNFE/IAE #2
Got expected CNFE/IAE #3
Got expected LinkageError on DE
+Got DEO result DoubledExtendOkay 1
+Got LinkageError on GD
+Got LinkageError on TA
Ctor: doubled implement, type 1
DoubledImplement one
Got LinkageError on DI (early)
diff --git a/tests/068-classloader/src-ex/AbstractGet.java b/tests/068-classloader/src-ex/AbstractGet.java
new file mode 100644
index 0000000..b62aa8f
--- /dev/null
+++ b/tests/068-classloader/src-ex/AbstractGet.java
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+/**
+ * Verify that we don't reject this with a LinkageError.
+ */
+public class AbstractGet extends AbstractBase {
+ public DoubledExtendOkay getExtended() {
+ return new DoubledExtendOkay();
+ }
+}
+
+/**
+ * Abstract class, does not declare getAbstract. This cause the VM to
+ * generate a "miranda" method.
+ */
+abstract class AbstractBase extends BaseOkay {
+ public abstract DoubledExtendOkay getExtended();
+}
+
diff --git a/tests/068-classloader/src-ex/DoubledExtendOkay.java b/tests/068-classloader/src-ex/DoubledExtendOkay.java
new file mode 100644
index 0000000..766fa8e
--- /dev/null
+++ b/tests/068-classloader/src-ex/DoubledExtendOkay.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/**
+ * "Okay" doubled sub-class, form #2.
+ */
+public class DoubledExtendOkay extends BaseOkay {
+ public DoubledExtendOkay() {
+ //System.out.println("Ctor: doubled extend okay, type 2");
+ }
+
+ /*
+ @Override
+ public DoubledExtendOkay getExtended() {
+ //System.out.println("getExtended 2");
+ return new DoubledExtendOkay();
+ }
+ */
+
+ public String getStr() {
+ return "DoubledExtendOkay 2";
+ }
+}
+
diff --git a/tests/068-classloader/src-ex/GetDoubled.java b/tests/068-classloader/src-ex/GetDoubled.java
new file mode 100644
index 0000000..5e20441
--- /dev/null
+++ b/tests/068-classloader/src-ex/GetDoubled.java
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+/*
+ * The interface we implement was declared in a different class loader,
+ * which means the DoubledExtend we return is not the one it was declared
+ * to return.
+ */
+public class GetDoubled implements IGetDoubled {
+ public DoubledExtendOkay getDoubled() {
+ return new DoubledExtendOkay();
+ }
+}
+
diff --git a/tests/068-classloader/src/BaseOkay.java b/tests/068-classloader/src/BaseOkay.java
new file mode 100644
index 0000000..c5c3f7a
--- /dev/null
+++ b/tests/068-classloader/src/BaseOkay.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+/**
+ * Common base class.
+ */
+public class BaseOkay implements IDoubledExtendOkay {
+ public BaseOkay() {}
+
+ public DoubledExtendOkay getExtended() {
+ return new DoubledExtendOkay();
+ }
+
+ public static String doStuff(DoubledExtendOkay dt) {
+ return dt.getStr();
+ }
+}
+
+/**
+ * Interface that declares the not-overridden method. This exists to ensure
+ * that the existence of an interface doesn't trip the check.
+ */
+interface IDoubledExtendOkay {
+ public DoubledExtendOkay getExtended();
+}
+
diff --git a/tests/068-classloader/src/DoubledExtendOkay.java b/tests/068-classloader/src/DoubledExtendOkay.java
new file mode 100644
index 0000000..e8ff404
--- /dev/null
+++ b/tests/068-classloader/src/DoubledExtendOkay.java
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/**
+ * "Okay" doubled sub-class, form #1.
+ */
+public class DoubledExtendOkay extends BaseOkay {
+ public DoubledExtendOkay() {
+ //System.out.println("Ctor: doubled extend okay, type 1");
+ }
+
+ /*
+ @Override
+ public DoubledExtendOkay getExtended() {
+ System.out.println("getExtended 1");
+ return new DoubledExtendOkay();
+ }
+ */
+
+ public String getStr() {
+ return "DoubledExtendOkay 1";
+ }
+}
+
diff --git a/tests/068-classloader/src/FancyLoader.java b/tests/068-classloader/src/FancyLoader.java
index 491fd5c..1daf155 100644
--- a/tests/068-classloader/src/FancyLoader.java
+++ b/tests/068-classloader/src/FancyLoader.java
@@ -1,4 +1,18 @@
-// Copyright 2008 The Android Open Source Project
+/*
+ * 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.
+ */
import java.io.File;
import java.io.FileNotFoundException;
@@ -29,6 +43,8 @@
/* on Dalvik, this is a DexFile; otherwise, it's null */
private Class mDexClass;
+ private Object mDexFile;
+
/**
* Construct FancyLoader, grabbing a reference to the DexFile class
* if we're running under Dalvik.
@@ -64,26 +80,29 @@
private Class<?> findClassDalvik(String name)
throws ClassNotFoundException {
- Constructor ctor;
- Object dexFile;
+ if (mDexFile == null) {
+ synchronized (FancyLoader.class) {
+ Constructor ctor;
+ /*
+ * Construct a DexFile object through reflection.
+ */
+ try {
+ ctor = mDexClass.getConstructor(new Class[] {String.class});
+ } catch (NoSuchMethodException nsme) {
+ throw new ClassNotFoundException("getConstructor failed",
+ nsme);
+ }
- /*
- * Construct a DexFile object through reflection.
- */
- try {
- ctor = mDexClass.getConstructor(new Class[] { String.class });
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getConstructor failed", nsme);
- }
-
- try {
- dexFile = ctor.newInstance(DEX_FILE);
- } catch (InstantiationException ie) {
- throw new ClassNotFoundException("newInstance failed", ie);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("newInstance failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("newInstance failed", ite);
+ try {
+ mDexFile = ctor.newInstance(DEX_FILE);
+ } catch (InstantiationException ie) {
+ throw new ClassNotFoundException("newInstance failed", ie);
+ } catch (IllegalAccessException iae) {
+ throw new ClassNotFoundException("newInstance failed", iae);
+ } catch (InvocationTargetException ite) {
+ throw new ClassNotFoundException("newInstance failed", ite);
+ }
+ }
}
/*
@@ -99,7 +118,7 @@
}
try {
- meth.invoke(dexFile, name, this);
+ meth.invoke(mDexFile, name, this);
} catch (IllegalAccessException iae) {
throw new ClassNotFoundException("loadClass failed", iae);
} catch (InvocationTargetException ite) {
diff --git a/tests/068-classloader/src/IGetDoubled.java b/tests/068-classloader/src/IGetDoubled.java
new file mode 100644
index 0000000..0a4ac91
--- /dev/null
+++ b/tests/068-classloader/src/IGetDoubled.java
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+/**
+ * Interface, loaded from one loader, used from another.
+ */
+public interface IGetDoubled {
+ public DoubledExtendOkay getDoubled();
+}
+
diff --git a/tests/068-classloader/src/Main.java b/tests/068-classloader/src/Main.java
index f8698be..0788b52 100644
--- a/tests/068-classloader/src/Main.java
+++ b/tests/068-classloader/src/Main.java
@@ -25,6 +25,8 @@
FancyLoader loader;
loader = new FancyLoader(ClassLoader.getSystemClassLoader());
+ //System.out.println("SYSTEM: " + ClassLoader.getSystemClassLoader());
+ //System.out.println("ALTERN: " + loader);
/*
* This statement has no effect on this program, but it can
@@ -51,6 +53,9 @@
testAccess3(loader);
testExtend(loader);
+ testExtendOkay(loader);
+ testInterface(loader);
+ testAbstract(loader);
testImplement(loader);
testIfaceImplement(loader);
}
@@ -175,6 +180,146 @@
}
/**
+ * Test a doubled class that extends the base class, but is okay since
+ * it doesn't override the base class method.
+ */
+ static void testExtendOkay(ClassLoader loader) {
+ Class doubledExtendOkayClass;
+ Object obj;
+
+ /* get the "alternate" version of DoubledExtendOkay */
+ try {
+ doubledExtendOkayClass = loader.loadClass("DoubledExtendOkay");
+ } catch (ClassNotFoundException cnfe) {
+ System.err.println("loadClass failed: " + cnfe);
+ return;
+ }
+
+ /* instantiate */
+ try {
+ obj = doubledExtendOkayClass.newInstance();
+ } catch (InstantiationException ie) {
+ System.err.println("newInstance failed: " + ie);
+ return;
+ } catch (IllegalAccessException iae) {
+ System.err.println("newInstance failed: " + iae);
+ return;
+ } catch (LinkageError le) {
+ System.err.println("Got unexpected LinkageError on DEO");
+ le.printStackTrace();
+ return;
+ }
+
+ /* use the base class reference to get a CL-specific instance */
+ BaseOkay baseRef = (BaseOkay) obj;
+ DoubledExtendOkay de = baseRef.getExtended();
+
+ /* try to call through it */
+ try {
+ String result;
+
+ result = BaseOkay.doStuff(de);
+ System.out.println("Got DEO result " + result);
+ } catch (LinkageError le) {
+ System.err.println("Got unexpected LinkageError on DEO");
+ le.printStackTrace();
+ return;
+ }
+ }
+
+ /**
+ * Try to access a doubled class through a class that implements
+ * an interface declared in a different class.
+ */
+ static void testInterface(ClassLoader loader) {
+ Class getDoubledClass;
+ Object obj;
+
+ /* get GetDoubled from the "alternate" class loader */
+ try {
+ getDoubledClass = loader.loadClass("GetDoubled");
+ } catch (ClassNotFoundException cnfe) {
+ System.err.println("loadClass failed: " + cnfe);
+ return;
+ }
+
+ /* instantiate */
+ try {
+ obj = getDoubledClass.newInstance();
+ } catch (InstantiationException ie) {
+ System.err.println("newInstance failed: " + ie);
+ return;
+ } catch (IllegalAccessException iae) {
+ System.err.println("newInstance failed: " + iae);
+ return;
+ } catch (LinkageError le) {
+ // Dalvik bails here
+ System.out.println("Got LinkageError on GD");
+ return;
+ }
+
+ /*
+ * Cast the object to the interface, and try to use it.
+ */
+ IGetDoubled iface = (IGetDoubled) obj;
+ try {
+ /* "de" will be the wrong variety of DoubledExtendOkay */
+ DoubledExtendOkay de = iface.getDoubled();
+ // reference impl bails here
+ String str = de.getStr();
+ } catch (LinkageError le) {
+ System.out.println("Got LinkageError on GD");
+ return;
+ }
+ System.err.println("Should have failed by now on GetDoubled");
+ }
+
+ /**
+ * Throw an abstract class into the middle and see what happens.
+ */
+ static void testAbstract(ClassLoader loader) {
+ Class abstractGetClass;
+ Object obj;
+
+ /* get AbstractGet from the "alternate" loader */
+ try {
+ abstractGetClass = loader.loadClass("AbstractGet");
+ } catch (ClassNotFoundException cnfe) {
+ System.err.println("loadClass ta failed: " + cnfe);
+ return;
+ }
+
+ /* instantiate */
+ try {
+ obj = abstractGetClass.newInstance();
+ } catch (InstantiationException ie) {
+ System.err.println("newInstance failed: " + ie);
+ return;
+ } catch (IllegalAccessException iae) {
+ System.err.println("newInstance failed: " + iae);
+ return;
+ } catch (LinkageError le) {
+ System.out.println("Got LinkageError on TA");
+ return;
+ }
+
+ /* use the base class reference to get a CL-specific instance */
+ BaseOkay baseRef = (BaseOkay) obj;
+ DoubledExtendOkay de = baseRef.getExtended();
+
+ /* try to call through it */
+ try {
+ String result;
+
+ result = BaseOkay.doStuff(de);
+ } catch (LinkageError le) {
+ System.out.println("Got LinkageError on TA");
+ return;
+ }
+ System.err.println("Should have failed by now in testAbstract");
+ }
+
+ /**
* Test a doubled class that implements a common interface.
*/
static void testImplement(ClassLoader loader) {
diff --git a/tests/071-dexfile/info.txt b/tests/071-dexfile/info.txt
index 5eb0489..54d9ed0 100644
--- a/tests/071-dexfile/info.txt
+++ b/tests/071-dexfile/info.txt
@@ -1,2 +1,4 @@
Exercise some Dalvik-specific DEX file features. This is not expected to
work on other VMs.
+
+NOTE: the test requires that /sdcard exists and is writable.
diff --git a/tests/071-dexfile/src/Main.java b/tests/071-dexfile/src/Main.java
index 0e6cce7..42c841d 100644
--- a/tests/071-dexfile/src/Main.java
+++ b/tests/071-dexfile/src/Main.java
@@ -15,6 +15,7 @@
*/
import java.io.File;
+import java.io.IOException;
import java.lang.reflect.Constructor;
/**
@@ -28,10 +29,49 @@
private static final String LIB_DIR = "/nowhere/nothing/";
/**
+ * Prep the environment then run the test.
+ */
+ public static void main(String[] args) {
+ Process p;
+ try {
+ /*
+ * Create a sub-process to see if the ProcessManager wait
+ * interferes with the dexopt invocation wait.
+ *
+ * /dev/random never hits EOF, so we're sure that we'll still
+ * be waiting for the process to complete. On the device it
+ * stops pretty quickly (which means the child won't be
+ * spinning).
+ */
+ ProcessBuilder pb = new ProcessBuilder("cat", "/dev/random");
+ p = pb.start();
+ } catch (IOException ioe) {
+ System.err.println("cmd failed: " + ioe.getMessage());
+ p = null;
+ }
+
+ try {
+ testDexClassLoader();
+ } finally {
+ // shouldn't be necessary, but it's good to be tidy
+ if (p != null)
+ p.destroy();
+
+ // let the ProcessManager's daemon thread finish before we shut down
+ // (avoids the occasional segmentation fault)
+ try {
+ Thread.sleep(500);
+ } catch (Exception ex) {}
+ }
+
+ System.out.println("done");
+ }
+
+ /**
* Create a class loader, explicitly specifying the source DEX and
* the location for the optimized DEX.
*/
- public static void main(String[] args) {
+ private static void testDexClassLoader() {
ClassLoader dexClassLoader = getDexClassLoader();
Class anotherClass;
@@ -50,10 +90,8 @@
throw new RuntimeException("new another", ie);
}
- /* not expected to work; just exercises the call */
+ // not expected to work; just exercises the call
dexClassLoader.getResource("nonexistent");
-
- System.out.println("done");
}
/*
@@ -94,6 +132,7 @@
throw new RuntimeException("DCL ctor", nsme);
}
+ // create an instance, using the path we found
Object dclObj;
try {
dclObj = ctor.newInstance(CLASS_PATH, odexDir, LIB_DIR, myLoader);
diff --git a/tests/072-precise-gc/expected.txt b/tests/072-precise-gc/expected.txt
new file mode 100644
index 0000000..18ec087
--- /dev/null
+++ b/tests/072-precise-gc/expected.txt
@@ -0,0 +1,2 @@
+Valid refs: 0
+String0String1String2String3String4String5String6String7String8String9
diff --git a/tests/072-precise-gc/info.txt b/tests/072-precise-gc/info.txt
new file mode 100644
index 0000000..b0b2cea
--- /dev/null
+++ b/tests/072-precise-gc/info.txt
@@ -0,0 +1 @@
+Try to detect whether precise GC is working.
diff --git a/tests/072-precise-gc/src/Main.java b/tests/072-precise-gc/src/Main.java
new file mode 100644
index 0000000..9b2315d
--- /dev/null
+++ b/tests/072-precise-gc/src/Main.java
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+import java.lang.ref.WeakReference;
+
+public class Main {
+ public static void main(String[] args) {
+ staleStackTest();
+ }
+
+ public static void staleStackTest() {
+ WeakReference wrefs[] = new WeakReference[10];
+
+ populate(wrefs);
+
+ check(wrefs);
+ }
+
+ static void populate(WeakReference[] wrefs) {
+ /*
+ * Get a bunch of non-constant String objects into registers. These
+ * should be the first locals declared.
+ */
+ String str0 = generateString("String", 0);
+ String str1 = generateString("String", 1);
+ String str2 = generateString("String", 2);
+ String str3 = generateString("String", 3);
+ String str4 = generateString("String", 4);
+ String str5 = generateString("String", 5);
+ String str6 = generateString("String", 6);
+ String str7 = generateString("String", 7);
+ String str8 = generateString("String", 8);
+ String str9 = generateString("String", 9);
+
+ /* stuff them into the weak references array */
+ wrefs[0] = new WeakReference(str0);
+ wrefs[1] = new WeakReference(str1);
+ wrefs[2] = new WeakReference(str2);
+ wrefs[3] = new WeakReference(str3);
+ wrefs[4] = new WeakReference(str4);
+ wrefs[5] = new WeakReference(str5);
+ wrefs[6] = new WeakReference(str6);
+ wrefs[7] = new WeakReference(str7);
+ wrefs[8] = new WeakReference(str8);
+ wrefs[9] = new WeakReference(str9);
+ }
+
+ static String generateString(String base, int num) {
+ return base + num;
+ }
+
+ static void check(WeakReference[] wrefs) {
+ /*
+ * Declare locals so that our stack overlaps the same region
+ * that populate() did.
+ */
+ String str0;
+ String str1;
+ String str2;
+ String str3;
+ String str4;
+ String str5;
+ String str6;
+ String str7;
+ String str8;
+ String str9;
+ int numValid = 0;
+
+ /*
+ * This *should* blow out all the weakly-reference objects. If
+ * we still have stale copies of references on the stack, a
+ * conservative GC will try to hold on to those objects and the
+ * count will be nonzero.
+ *
+ * Getting a zero result here isn't conclusive, but it's a strong
+ * indicator that precise GC is having an impact.
+ */
+ System.gc();
+
+ for (int i = 0; i < wrefs.length; i++) {
+ if (wrefs[i].get() != null)
+ numValid++;
+ }
+
+ System.out.println("Valid refs: " + numValid);
+
+ /* use the locals in case the compiler gets smart */
+ str0 = generateString("String", 0);
+ str1 = generateString("String", 1);
+ str2 = generateString("String", 2);
+ str3 = generateString("String", 3);
+ str4 = generateString("String", 4);
+ str5 = generateString("String", 5);
+ str6 = generateString("String", 6);
+ str7 = generateString("String", 7);
+ str8 = generateString("String", 8);
+ str9 = generateString("String", 9);
+ System.out.println(str0+str1+str2+str3+str4+str5+str6+str7+str8+str9);
+ }
+}
+
diff --git a/tests/073-mismatched-field/expected.txt b/tests/073-mismatched-field/expected.txt
new file mode 100644
index 0000000..90fbab8
--- /dev/null
+++ b/tests/073-mismatched-field/expected.txt
@@ -0,0 +1 @@
+Got expected failure
diff --git a/tests/073-mismatched-field/info.txt b/tests/073-mismatched-field/info.txt
new file mode 100644
index 0000000..4a15263
--- /dev/null
+++ b/tests/073-mismatched-field/info.txt
@@ -0,0 +1,3 @@
+Test behavior when an instance field is overlapped (through separate
+compilation) by a static field. The VM is expected to detect the conflict
+and throw an IncompatibleClassChangeError when the field is accessed.
diff --git a/tests/073-mismatched-field/src/IMain.java b/tests/073-mismatched-field/src/IMain.java
new file mode 100644
index 0000000..301dd21
--- /dev/null
+++ b/tests/073-mismatched-field/src/IMain.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+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
new file mode 100644
index 0000000..fb9f32a
--- /dev/null
+++ b/tests/073-mismatched-field/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+public class Main extends SuperMain implements IMain {
+ public static void main(String[] args) {
+ Main main = new Main();
+ main.doit();
+ }
+
+ void doit() {
+ try {
+ System.out.println("value=" + this.f);
+ System.err.println("Succeeded unexpectedly");
+ } catch (IncompatibleClassChangeError icce) {
+ System.out.println("Got expected failure");
+ }
+ }
+}
+
diff --git a/tests/073-mismatched-field/src/SuperMain.java b/tests/073-mismatched-field/src/SuperMain.java
new file mode 100644
index 0000000..7447739
--- /dev/null
+++ b/tests/073-mismatched-field/src/SuperMain.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+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
new file mode 100644
index 0000000..585c738
--- /dev/null
+++ b/tests/073-mismatched-field/src2/IMain.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+public interface IMain {
+ static int f = 123;
+}
+
diff --git a/tests/074-gc-thrash/expected.txt b/tests/074-gc-thrash/expected.txt
new file mode 100644
index 0000000..2669165
--- /dev/null
+++ b/tests/074-gc-thrash/expected.txt
@@ -0,0 +1,2 @@
+Running (10 seconds) ...
+Done.
diff --git a/tests/074-gc-thrash/info.txt b/tests/074-gc-thrash/info.txt
new file mode 100644
index 0000000..c195adb
--- /dev/null
+++ b/tests/074-gc-thrash/info.txt
@@ -0,0 +1,2 @@
+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
new file mode 100644
index 0000000..f79e5ce
--- /dev/null
+++ b/tests/074-gc-thrash/src/Main.java
@@ -0,0 +1,338 @@
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+
+public class Main {
+ public static volatile boolean quit = false;
+ public static final boolean DEBUG = false;
+
+ private static final boolean WRITE_HPROF_DATA = false;
+ private static final int TEST_TIME = 10;
+ private static final String OUTPUT_FILE = "gc-thrash.hprof";
+
+ public static void main(String[] args) {
+ // dump heap before
+
+ System.out.println("Running (" + TEST_TIME + " seconds) ...");
+ runTests();
+
+ Method dumpHprofDataMethod = null;
+ String dumpFile = null;
+
+ if (WRITE_HPROF_DATA) {
+ dumpHprofDataMethod = getDumpHprofDataMethod();
+ if (dumpHprofDataMethod != null) {
+ dumpFile = getDumpFileName();
+ System.out.println("Sending output to " + dumpFile);
+ }
+ }
+
+ System.gc();
+ System.runFinalization();
+ System.gc();
+
+ if (WRITE_HPROF_DATA && dumpHprofDataMethod != null) {
+ try {
+ dumpHprofDataMethod.invoke(null, dumpFile);
+ } catch (IllegalAccessException iae) {
+ System.err.println(iae);
+ } catch (InvocationTargetException ite) {
+ System.err.println(ite);
+ }
+ }
+
+ System.out.println("Done.");
+ }
+
+ /**
+ * Finds VMDebug.dumpHprofData() through reflection. In the reference
+ * implementation this will not be available.
+ *
+ * @return the reflection object, or null if the method can't be found
+ */
+ private static Method getDumpHprofDataMethod() {
+ ClassLoader myLoader = Main.class.getClassLoader();
+ Class vmdClass;
+ try {
+ vmdClass = myLoader.loadClass("dalvik.system.VMDebug");
+ } catch (ClassNotFoundException cnfe) {
+ return null;
+ }
+
+ Method meth;
+ try {
+ meth = vmdClass.getMethod("dumpHprofData",
+ new Class[] { String.class });
+ } catch (NoSuchMethodException nsme) {
+ System.err.println("Found VMDebug but not dumpHprofData method");
+ return null;
+ }
+
+ return meth;
+ }
+
+ private static String getDumpFileName() {
+ File tmpDir = new File("/tmp");
+ if (tmpDir.exists() && tmpDir.isDirectory()) {
+ return "/tmp/" + OUTPUT_FILE;
+ }
+
+ File sdcard = new File("/sdcard");
+ if (sdcard.exists() && sdcard.isDirectory()) {
+ return "/sdcard/" + OUTPUT_FILE;
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Run the various tests for a set period.
+ */
+ public static void runTests() {
+ Robin robin = new Robin();
+ Deep deep = new Deep();
+ Large large = new Large();
+
+ /* start all threads */
+ robin.start();
+ deep.start();
+ large.start();
+
+ /* let everybody run for 10 seconds */
+ sleep(TEST_TIME * 1000);
+
+ quit = true;
+
+ try {
+ /* wait for all threads to stop */
+ robin.join();
+ deep.join();
+ large.join();
+ } catch (InterruptedException ie) {
+ System.err.println("join was interrupted");
+ }
+ }
+
+ /**
+ * Sleeps for the "ms" milliseconds.
+ */
+ public static void sleep(int ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (InterruptedException ie) {
+ System.err.println("sleep was interrupted");
+ }
+ }
+
+ /**
+ * Sleeps briefly, allowing other threads some CPU time to get started.
+ */
+ public static void startupDelay() {
+ sleep(500);
+ }
+}
+
+
+/**
+ * Allocates useless objects and holds on to several of them.
+ *
+ * Uses a single large array of references, replaced repeatedly in round-robin
+ * order.
+ */
+class Robin extends Thread {
+ private static final int ARRAY_SIZE = 40960;
+ int sleepCount = 0;
+
+ public void run() {
+ Main.startupDelay();
+
+ String strings[] = new String[ARRAY_SIZE];
+ int idx = 0;
+
+ while (!Main.quit) {
+ strings[idx] = makeString(idx);
+
+ if (idx % (ARRAY_SIZE / 4) == 0) {
+ Main.sleep(400);
+ sleepCount++;
+ }
+
+ idx = (idx + 1) % ARRAY_SIZE;
+ }
+
+ if (Main.DEBUG)
+ System.out.println("Robin: sleepCount=" + sleepCount);
+ }
+
+ private String makeString(int val) {
+ return new String("Robin" + val);
+ }
+}
+
+
+/**
+ * Allocates useless objects in recursive calls.
+ */
+class Deep extends Thread {
+ private static final int MAX_DEPTH = 61;
+
+ private static String strong[] = new String[MAX_DEPTH];
+ private static WeakReference weak[] = new WeakReference[MAX_DEPTH];
+
+ public void run() {
+ int iter = 0;
+ boolean once = false;
+
+ Main.startupDelay();
+
+ while (!Main.quit) {
+ dive(0, iter);
+ once = true;
+ iter += MAX_DEPTH;
+ }
+
+ if (!once) {
+ System.err.println("not even once?");
+ return;
+ }
+
+ /*
+ * Check the results of the last trip through. Everything in
+ * "weak" should be matched in "strong", and the two should be
+ * equivalent (object-wise, not just string-equality-wise).
+ */
+ for (int i = 0; i < MAX_DEPTH; i++) {
+ if (strong[i] != weak[i].get()) {
+ System.err.println("Deep: " + i + " strong=" + strong[i] +
+ ", weak=" + weak[i].get());
+ }
+ }
+
+ /*
+ * Wipe "strong", do a GC, see if "weak" got collected.
+ */
+ for (int i = 0; i < MAX_DEPTH; i++)
+ strong[i] = null;
+
+ System.gc();
+
+ for (int i = 0; i < MAX_DEPTH; i++) {
+ if (weak[i].get() != null) {
+ System.err.println("Deep: weak still has " + i);
+ }
+ }
+
+ if (Main.DEBUG)
+ System.out.println("Deep: iters=" + iter / MAX_DEPTH);
+ }
+
+ /**
+ * Recursively dive down, setting one or more local variables.
+ *
+ * We pad the stack out with locals, attempting to create a mix of
+ * valid and invalid references on the stack.
+ */
+ private String dive(int depth, int iteration) {
+ String str0;
+ String str1;
+ String str2;
+ String str3;
+ String str4;
+ String str5;
+ String str6;
+ String str7;
+ String funStr;
+
+ funStr = "";
+
+ switch (iteration % 8) {
+ case 0:
+ funStr = str0 = makeString(iteration);
+ break;
+ case 1:
+ funStr = str1 = makeString(iteration);
+ break;
+ case 2:
+ funStr = str2 = makeString(iteration);
+ break;
+ case 3:
+ funStr = str3 = makeString(iteration);
+ break;
+ case 4:
+ funStr = str4 = makeString(iteration);
+ break;
+ case 5:
+ funStr = str5 = makeString(iteration);
+ break;
+ case 6:
+ funStr = str6 = makeString(iteration);
+ break;
+ case 7:
+ funStr = str7 = makeString(iteration);
+ break;
+ }
+
+ strong[depth] = funStr;
+ weak[depth] = new WeakReference(funStr);
+
+ if (depth+1 < MAX_DEPTH)
+ dive(depth+1, iteration+1);
+ else
+ Main.sleep(100);
+
+ return funStr;
+ }
+
+ private String makeString(int val) {
+ return new String("Deep" + val);
+ }
+}
+
+
+/**
+ * Allocates large useless objects.
+ */
+class Large extends Thread {
+ public void run() {
+ byte[] chunk;
+ int count = 0;
+ int sleepCount = 0;
+
+ Main.startupDelay();
+
+ while (!Main.quit) {
+ chunk = new byte[100000];
+ pretendToUse(chunk);
+
+ count++;
+ if ((count % 500) == 0) {
+ Main.sleep(400);
+ sleepCount++;
+ }
+ }
+
+ if (Main.DEBUG)
+ System.out.println("Large: sleepCount=" + sleepCount);
+ }
+
+ public void pretendToUse(byte[] chunk) {}
+}
+
diff --git a/tests/075-verification-error/expected.txt b/tests/075-verification-error/expected.txt
new file mode 100644
index 0000000..3e8dbd0
--- /dev/null
+++ b/tests/075-verification-error/expected.txt
@@ -0,0 +1,11 @@
+Got expected InstantationError
+Got expected NoSuchFieldError
+Got expected NoSuchFieldError
+Got expected NoSuchMethodError
+Got expected NoSuchMethodError
+Got expected IllegalAccessError (ifield)
+Got expected IllegalAccessError (sfield)
+Got expected IllegalAccessError (method)
+Got expected IllegalAccessError (smethod)
+Got expected IllegalAccessError (meth-class)
+Got expected IllegalAccessError (meth-meth)
diff --git a/tests/075-verification-error/info.txt b/tests/075-verification-error/info.txt
new file mode 100644
index 0000000..be688ff
--- /dev/null
+++ b/tests/075-verification-error/info.txt
@@ -0,0 +1 @@
+Exercise deferred verification error reporting.
diff --git a/tests/075-verification-error/src/Main.java b/tests/075-verification-error/src/Main.java
new file mode 100644
index 0000000..8a0dd15
--- /dev/null
+++ b/tests/075-verification-error/src/Main.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+import other.Mutant;
+import other.InaccessibleClass;
+import other.InaccessibleMethod;
+
+/**
+ * Test some problematic situations that the verifier detects.
+ */
+public class Main {
+ public static final boolean VERBOSE = false;
+
+ public static void main(String[] args) {
+ testClassNewInstance();
+ testMissingStuff();
+ testBadAccess();
+ }
+
+ /**
+ * Try to create a new instance of an abstract class.
+ */
+ static void testClassNewInstance() {
+ try {
+ MaybeAbstract ma = new MaybeAbstract();
+ System.err.println("ERROR: MaybeAbstract succeeded unexpectedly");
+ } catch (InstantiationError ie) {
+ System.out.println("Got expected InstantationError");
+ if (VERBOSE) System.out.println("--- " + ie);
+ } catch (Exception ex) {
+ System.err.println("Got unexpected MaybeAbstract failure");
+ }
+ }
+
+ /**
+ * Test stuff that disappears.
+ */
+ static void testMissingStuff() {
+ Mutant mutant = new Mutant();
+
+ try {
+ int x = mutant.disappearingField;
+ } catch (NoSuchFieldError nsfe) {
+ System.out.println("Got expected NoSuchFieldError");
+ if (VERBOSE) System.out.println("--- " + nsfe);
+ }
+
+ try {
+ int y = Mutant.disappearingStaticField;
+ } catch (NoSuchFieldError nsfe) {
+ System.out.println("Got expected NoSuchFieldError");
+ if (VERBOSE) System.out.println("--- " + nsfe);
+ }
+
+ try {
+ mutant.disappearingMethod();
+ } catch (NoSuchMethodError nsme) {
+ System.out.println("Got expected NoSuchMethodError");
+ if (VERBOSE) System.out.println("--- " + nsme);
+ }
+
+ try {
+ Mutant.disappearingStaticMethod();
+ } catch (NoSuchMethodError nsme) {
+ System.out.println("Got expected NoSuchMethodError");
+ if (VERBOSE) System.out.println("--- " + nsme);
+ }
+ }
+
+ /**
+ * Test stuff that becomes inaccessible.
+ */
+ static void testBadAccess() {
+ Mutant mutant = new Mutant();
+
+ try {
+ int x = mutant.inaccessibleField;
+ System.err.println("ERROR: bad access succeeded\n");
+ } catch (IllegalAccessError iae) {
+ System.out.println("Got expected IllegalAccessError (ifield)");
+ if (VERBOSE) System.out.println("--- " + iae);
+ }
+
+ try {
+ int y = Mutant.inaccessibleStaticField;
+ System.err.println("ERROR: bad access succeeded\n");
+ } catch (IllegalAccessError iae) {
+ System.out.println("Got expected IllegalAccessError (sfield)");
+ if (VERBOSE) System.out.println("--- " + iae);
+ }
+
+ try {
+ mutant.inaccessibleMethod();
+ System.err.println("ERROR: bad access succeeded\n");
+ } catch (IllegalAccessError iae) {
+ System.out.println("Got expected IllegalAccessError (method)");
+ if (VERBOSE) System.out.println("--- " + iae);
+ }
+
+ try {
+ Mutant.inaccessibleStaticMethod();
+ System.err.println("ERROR: bad access succeeded\n");
+ } catch (IllegalAccessError iae) {
+ System.out.println("Got expected IllegalAccessError (smethod)");
+ if (VERBOSE) System.out.println("--- " + iae);
+ }
+
+ try {
+ /* accessible static method in an inaccessible class */
+ InaccessibleClass.test();
+ System.err.println("ERROR: bad access succeeded\n");
+ } catch (IllegalAccessError iae) {
+ System.out.println("Got expected IllegalAccessError (meth-class)");
+ if (VERBOSE) System.out.println("--- " + iae);
+ }
+
+ try {
+ /* inaccessible static method in an accessible class */
+ InaccessibleMethod.test();
+ System.err.println("ERROR: bad access succeeded\n");
+ } catch (IllegalAccessError iae) {
+ System.out.println("Got expected IllegalAccessError (meth-meth)");
+ if (VERBOSE) System.out.println("--- " + iae);
+ }
+ }
+}
+
diff --git a/tests/075-verification-error/src/MaybeAbstract.java b/tests/075-verification-error/src/MaybeAbstract.java
new file mode 100644
index 0000000..43c002b
--- /dev/null
+++ b/tests/075-verification-error/src/MaybeAbstract.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public /*abstract*/ class MaybeAbstract {
+ 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
new file mode 100644
index 0000000..79ad335
--- /dev/null
+++ b/tests/075-verification-error/src/other/InaccessibleClass.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package other;
+
+public class InaccessibleClass {
+ public static void test() {}
+}
+
diff --git a/tests/075-verification-error/src/other/InaccessibleMethod.java b/tests/075-verification-error/src/other/InaccessibleMethod.java
new file mode 100644
index 0000000..49a0b29
--- /dev/null
+++ b/tests/075-verification-error/src/other/InaccessibleMethod.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package other;
+
+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
new file mode 100644
index 0000000..6c869c0
--- /dev/null
+++ b/tests/075-verification-error/src/other/Mutant.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package other;
+
+/**
+ * Parts of this class will disappear or change form.
+ */
+public class Mutant {
+ public int disappearingField = 3;
+ public static int disappearingStaticField = 4;
+
+ public void disappearingMethod() {
+ System.out.println("bye");
+ }
+ public static void disappearingStaticMethod() {
+ System.out.println("kthxbai");
+ }
+
+ public int inaccessibleField = 5;
+ public static int inaccessibleStaticField = 6;
+
+ public void inaccessibleMethod() {
+ System.out.println("no");
+ }
+
+ public static void inaccessibleStaticMethod() {
+ System.out.println("nay");
+ }
+}
+
diff --git a/tests/075-verification-error/src2/MaybeAbstract.java b/tests/075-verification-error/src2/MaybeAbstract.java
new file mode 100644
index 0000000..bfbfd45
--- /dev/null
+++ b/tests/075-verification-error/src2/MaybeAbstract.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+public abstract class MaybeAbstract {
+ 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
new file mode 100644
index 0000000..c598910
--- /dev/null
+++ b/tests/075-verification-error/src2/other/InaccessibleClass.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package other;
+
+/*package*/ class InaccessibleClass {
+ public static void test() {}
+}
+
diff --git a/tests/075-verification-error/src2/other/InaccessibleMethod.java b/tests/075-verification-error/src2/other/InaccessibleMethod.java
new file mode 100644
index 0000000..6e2738e
--- /dev/null
+++ b/tests/075-verification-error/src2/other/InaccessibleMethod.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package other;
+
+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
new file mode 100644
index 0000000..220fda0
--- /dev/null
+++ b/tests/075-verification-error/src2/other/Mutant.java
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package other;
+
+/**
+ * Parts of this class will disappear or change form.
+ */
+public class Mutant {
+ //public int disappearingField = 3;
+ //public static int disappearingStaticField = 4;
+
+ //public static void disappearingMethod() {
+ // System.out.println("bye");
+ //}
+ //public static void disappearingStaticMethod() {
+ // System.out.println("kthxbai");
+ //}
+
+ protected int inaccessibleField = 5;
+ protected static int inaccessibleStaticField = 6;
+
+ protected void inaccessibleMethod() {
+ System.out.println("no");
+ }
+
+ protected static void inaccessibleStaticMethod() {
+ System.out.println("nay");
+ }
+}
+
+
diff --git a/tests/076-boolean-put/expected.txt b/tests/076-boolean-put/expected.txt
new file mode 100644
index 0000000..a965a70
--- /dev/null
+++ b/tests/076-boolean-put/expected.txt
@@ -0,0 +1 @@
+Done
diff --git a/tests/076-boolean-put/info.txt b/tests/076-boolean-put/info.txt
new file mode 100644
index 0000000..5b3ef4d
--- /dev/null
+++ b/tests/076-boolean-put/info.txt
@@ -0,0 +1,3 @@
+This checks a case where javac generates code that stores a byte into a
+boolean field. The code as generated should not pass the verifier, so the
+verifier had to be "loosened" to allow this case.
diff --git a/tests/076-boolean-put/src/Main.java b/tests/076-boolean-put/src/Main.java
new file mode 100644
index 0000000..b325422
--- /dev/null
+++ b/tests/076-boolean-put/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+/**
+ * Test access to private boolean fields.
+ *
+ * Accessing private boolean fields from an inner class causes the compiler
+ * to generate an accessor method that performs the boolean operation.
+ * Unfortunately the generated method takes an integer as an argument,
+ * not a boolean, which makes the verifier upset when the result of the
+ * operation is written back to a boolean field.
+ */
+public class Main {
+ private boolean mInstance;
+ private static boolean mStatic;
+
+ public static void main(String[] args) {
+ Main foo = new Main();
+ foo.test();
+
+ System.out.println("Done");
+ }
+
+ void test() {
+ Innard innard = new Innard();
+ innard.doStuff();
+ }
+
+ class Innard {
+ void doStuff() {
+ mInstance |= true;
+ mStatic |= true;
+ }
+ }
+}
diff --git a/tests/077-method-override/expected.txt b/tests/077-method-override/expected.txt
new file mode 100644
index 0000000..2e9bda3
--- /dev/null
+++ b/tests/077-method-override/expected.txt
@@ -0,0 +1,15 @@
+declaredInBase: Base
+notDeclaredInBase: Derived
+wasOverridden: Derived
+overrideWithPublic: Derived
+overrideProtectedWithPublic: Derived
+overridePublicWithProtected: Derived
+overridePublicWithPrivate: Base
+overridePrivateWithPublic: Base
+overridePrivateWithPublic: Derived
+overrideVirtualWithStatic: Base
+overrideVirtualWithStatic: Derived
+overrideStaticWithVirtual: Base
+overrideStaticWithVirtual: Derived
+Got expected exception - ovws
+Got expected exception - oswv
diff --git a/tests/077-method-override/info.txt b/tests/077-method-override/info.txt
new file mode 100644
index 0000000..914b4f2
--- /dev/null
+++ b/tests/077-method-override/info.txt
@@ -0,0 +1,2 @@
+Test various forms of method overrides, including some not allowed by the
+compiler but possible with separate compilation.
diff --git a/tests/077-method-override/src/Base.java b/tests/077-method-override/src/Base.java
new file mode 100644
index 0000000..eed6f22
--- /dev/null
+++ b/tests/077-method-override/src/Base.java
@@ -0,0 +1,84 @@
+/*
+ * 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.
+ */
+
+public class Base {
+ public void declaredInBase() {
+ System.out.println("declaredInBase: Base");
+ }
+
+ public void overridden() {
+ System.out.println("overridden: Base");
+ }
+
+ /* src2: removed */
+ public void wasOverridden() {
+ System.out.println("wasOverridden: Base");
+ }
+
+ public void callOverrideWithPublic() {
+ overrideWithPublic();
+ }
+ public void overrideWithPublic() {
+ System.out.println("overrideWithPublic: Base");
+ }
+
+ public void callOverridePublicWithProtected() {
+ overridePublicWithProtected();
+ }
+ /* src2: public */
+ protected void overridePublicWithProtected() {
+ System.out.println("overridePublicWithProtected: Base");
+ }
+
+ public void callOverrideProtectedWithPublic() {
+ overrideProtectedWithPublic();
+ }
+ protected void overrideProtectedWithPublic() {
+ System.out.println("overrideProtectedWithPublic: Base");
+ }
+
+ public void callOverridePublicWithPrivate() {
+ overridePublicWithPrivate();
+ }
+ /* src2: public */
+ private void overridePublicWithPrivate() {
+ System.out.println("overridePublicWithPrivate: Base");
+ }
+
+ public void callOverridePrivateWithPublic() {
+ overridePrivateWithPublic();
+ }
+ private void overridePrivateWithPublic() {
+ System.out.println("overridePrivateWithPublic: Base");
+ }
+
+ public void callOverrideVirtualWithStatic() {
+ overrideVirtualWithStatic();
+ }
+ /* src2: non-static */
+ public static void overrideVirtualWithStatic() {
+ System.out.println("overrideVirtualWithStatic: Base");
+ }
+
+ public void callOverrideStaticWithVirtual() {
+ overrideStaticWithVirtual();
+ }
+ /* src2: static */
+ public void overrideStaticWithVirtual() {
+ System.out.println("overrideStaticWithVirtual: Base");
+ }
+}
+
diff --git a/tests/077-method-override/src/Derived.java b/tests/077-method-override/src/Derived.java
new file mode 100644
index 0000000..09ffdf6
--- /dev/null
+++ b/tests/077-method-override/src/Derived.java
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+public class Derived extends Base {
+ public static void notDeclaredInBase() {
+ System.out.println("notDeclaredInBase: Derived");
+ }
+
+ public void overridden() {
+ System.out.println("overridden: Derived");
+ }
+
+ public void wasOverridden() {
+ System.out.println("wasOverridden: Derived");
+ }
+
+ public void overrideWithPublic() {
+ System.out.println("overrideWithPublic: Derived");
+ }
+
+ protected void overridePublicWithProtected() {
+ System.out.println("overridePublicWithProtected: Derived");
+ }
+
+ public void overrideProtectedWithPublic() {
+ System.out.println("overrideProtectedWithPublic: Derived");
+ }
+
+ private void overridePublicWithPrivate() {
+ System.out.println("overridePublicWithPrivate: Derived");
+ }
+
+ public void overridePrivateWithPublic() {
+ System.out.println("overridePrivateWithPublic: Derived");
+ }
+
+ /* not really an "override"; just has same method signature */
+ public static void overrideVirtualWithStatic() {
+ System.out.println("overrideVirtualWithStatic: Derived");
+ }
+
+ /* not really an "override"; just has same method signature */
+ public void overrideStaticWithVirtual() {
+ System.out.println("overrideStaticWithVirtual: Derived");
+ }
+}
+
diff --git a/tests/077-method-override/src/Main.java b/tests/077-method-override/src/Main.java
new file mode 100644
index 0000000..fa401cd
--- /dev/null
+++ b/tests/077-method-override/src/Main.java
@@ -0,0 +1,54 @@
+/*
+ * 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.
+ */
+
+public class Main {
+ public static void main(String args[]) {
+ Derived derived = new Derived();
+
+ derived.declaredInBase();
+ derived.notDeclaredInBase();
+ derived.wasOverridden();
+
+ derived.callOverrideWithPublic();
+ derived.callOverrideProtectedWithPublic();
+ derived.callOverridePublicWithProtected();
+ derived.callOverridePublicWithPrivate();
+ derived.callOverridePrivateWithPublic();
+ derived.overridePrivateWithPublic();
+ derived.callOverrideVirtualWithStatic();
+ derived.overrideVirtualWithStatic();
+ derived.callOverrideStaticWithVirtual();
+ derived.overrideStaticWithVirtual();
+
+ try {
+ ((Base)derived).overrideVirtualWithStatic();
+ } catch (NoSuchMethodError nsme) {
+ /* NSME is subclass of ICCE, so check it explicitly */
+ System.err.println("Got NSME - ovws");
+ } catch (IncompatibleClassChangeError icce) {
+ System.out.println("Got expected exception - ovws");
+ }
+
+ try {
+ ((Base)derived).overrideStaticWithVirtual();
+ } catch (NoSuchMethodError nsme) {
+ System.err.println("Got NSME - ovws");
+ } catch (IncompatibleClassChangeError icce) {
+ System.out.println("Got expected exception - oswv");
+ }
+ }
+}
+
diff --git a/tests/077-method-override/src2/Base.java b/tests/077-method-override/src2/Base.java
new file mode 100644
index 0000000..8be42bc
--- /dev/null
+++ b/tests/077-method-override/src2/Base.java
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+public class Base {
+ public void declaredInBase() {
+ System.out.println("declaredInBase: Base");
+ }
+
+ public void overridden() {
+ System.out.println("overridden: Base");
+ }
+
+ /* src2: removed */
+ //public void wasOverridden() {
+ // System.out.println("wasOverridden: Base");
+ //}
+
+ public void callOverrideWithPublic() {
+ overrideWithPublic();
+ }
+ public void overrideWithPublic() {
+ System.out.println("overrideWithPublic: Base");
+ }
+
+ public void callOverridePublicWithProtected() {
+ overridePublicWithProtected();
+ }
+ /* src2: public */
+ public void overridePublicWithProtected() {
+ System.out.println("overridePublicWithProtected: Base");
+ }
+
+ public void callOverrideProtectedWithPublic() {
+ overrideProtectedWithPublic();
+ }
+ protected void overrideProtectedWithPublic() {
+ System.out.println("overrideProtectedWithPublic: Base");
+ }
+
+ public void callOverridePublicWithPrivate() {
+ overridePublicWithPrivate();
+ }
+ /* src2: public */
+ public void overridePublicWithPrivate() {
+ System.out.println("overridePublicWithPrivate: Base");
+ }
+
+ public void callOverridePrivateWithPublic() {
+ overridePrivateWithPublic();
+ }
+ private void overridePrivateWithPublic() {
+ System.out.println("overridePrivateWithPublic: Base");
+ }
+
+ public void callOverrideVirtualWithStatic() {
+ overrideVirtualWithStatic();
+ }
+ /* src2: non-static */
+ public void overrideVirtualWithStatic() {
+ System.out.println("overrideVirtualWithStatic: Base");
+ }
+
+ public void callOverrideStaticWithVirtual() {
+ overrideStaticWithVirtual();
+ }
+ public static void overrideStaticWithVirtual() {
+ System.out.println("overrideStaticWithVirtual: Base");
+ }
+}
+
diff --git a/tests/etc/local-run-test-jar b/tests/etc/local-run-test-jar
index 0c802ba..ee3f856 100755
--- a/tests/etc/local-run-test-jar
+++ b/tests/etc/local-run-test-jar
@@ -26,6 +26,7 @@
VALGRIND="n"
DEV_MODE="n"
QUIET="n"
+PRECISE="y"
while true; do
if [ "x$1" = "x--quiet" ]; then
@@ -57,6 +58,9 @@
elif [ "x$1" = "x--no-optimize" ]; then
OPTIMIZE="n"
shift
+ elif [ "x$1" = "x--no-precise" ]; then
+ PRECISE="n"
+ shift
elif [ "x$1" = "x--" ]; then
shift
break
@@ -96,11 +100,17 @@
if [ "$VALGRIND" = "y" ]; then
msg "Running with valgrind"
valgrind_cmd="valgrind"
- #valgrind_cmd="$valgrind_cmd --leak-check=full"
+ #valgrind_cmd="valgrind --leak-check=full"
else
valgrind_cmd=""
fi
+if [ "$PRECISE" = "y" ]; then
+ GC_OPTS="-Xgc:precise -Xgenregmap"
+else
+ GC_OPTS="-Xgc:noprecise"
+fi
+
msg "------------------------------"
BASE="$OUT" # from build environment
@@ -109,9 +119,9 @@
export ANDROID_PRINTF_LOG=brief
if [ "$DEV_MODE" = "y" ]; then
- export ANDROID_LOG_TAGS='*:d'
+ export ANDROID_LOG_TAGS='*:d'
else
- export ANDROID_LOG_TAGS='*:s'
+ export ANDROID_LOG_TAGS='*:s'
fi
export ANDROID_DATA="$DATA_DIR"
export ANDROID_ROOT="${BASE}/system"
@@ -134,5 +144,5 @@
fi
$valgrind_cmd $gdb $exe $gdbargs "-Xbootclasspath:${bpath}" \
- $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG "-Xint:${INTERP}" -ea \
+ $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG $GC_OPTS "-Xint:${INTERP}" -ea \
-cp test.jar Main "$@"
diff --git a/tests/etc/push-and-run-test-jar b/tests/etc/push-and-run-test-jar
index c9bcfb2..db7addc 100755
--- a/tests/etc/push-and-run-test-jar
+++ b/tests/etc/push-and-run-test-jar
@@ -12,6 +12,7 @@
# --dev -- development mode
# --no-verify -- turn off verification (on by default)
# --no-optimize -- turn off optimization (on by default)
+# --no-precise -- turn off precise GC (on by default)
msg() {
if [ "$QUIET" = "n" ]; then
@@ -25,6 +26,7 @@
OPTIMIZE="y"
ZYGOTE="n"
QUIET="n"
+PRECISE="y"
while true; do
if [ "x$1" = "x--quiet" ]; then
@@ -54,6 +56,9 @@
elif [ "x$1" = "x--no-optimize" ]; then
OPTIMIZE="n"
shift
+ elif [ "x$1" = "x--no-precise" ]; then
+ PRECISE="n"
+ shift
elif [ "x$1" = "x--" ]; then
shift
break
@@ -106,9 +111,15 @@
DEX_DEBUG="-agentlib:jdwp=transport=dt_android_adb,server=y,suspend=y"
fi
+if [ "$PRECISE" = "y" ]; then
+ GC_OPTS="-Xgc:precise -Xgenregmap"
+else
+ GC_OPTS="-Xgc:noprecise"
+fi
+
if [ "$ZYGOTE" = "y" ]; then
adb shell cd /data \; dvz -classpath test.jar Main "$@"
else
adb shell cd /data \; dalvikvm $DEX_VERIFY $DEX_OPTIMIZE $DEX_DEBUG \
- -cp test.jar "-Xint:${INTERP}" -ea Main "$@"
+ $GC_OPTS -cp test.jar "-Xint:${INTERP}" -ea Main "$@"
fi
diff --git a/tests/run-test b/tests/run-test
index b503905..25bfb4e 100755
--- a/tests/run-test
+++ b/tests/run-test
@@ -79,6 +79,9 @@
elif [ "x$1" = "x--no-optimize" ]; then
run_args="${run_args} --no-optimize"
shift
+ elif [ "x$1" = "x--no-precise" ]; then
+ run_args="${run_args} --no-precise"
+ shift
elif [ "x$1" = "x--valgrind" ]; then
run_args="${run_args} --valgrind"
shift
@@ -146,6 +149,7 @@
#echo " --gdb Run under gdb; incompatible with some tests."
echo " --no-verify Turn off verification (on by default)."
echo " --no-optimize Turn off optimization (on by default)."
+ echo " --no-precise Turn off precise GC (on by default)."
echo " --zygote Spawn the process from the Zygote." \
"If used, then the"
echo " other runtime options are ignored."
diff --git a/tools/dexcheck b/tools/dexcheck
new file mode 100755
index 0000000..76662e8
--- /dev/null
+++ b/tools/dexcheck
@@ -0,0 +1,32 @@
+#!/bin/bash
+#
+# 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".
+
+# Get the list of files. Use "sed" to drop the trailing carriage return.
+files=`adb shell "cd /data/dalvik-cache; echo *" | sed -e s/.$//`
+if [ "$files" = "*" ]; then
+ echo 'ERROR: commands must run as root on device (try "adb root" first?)'
+ exit 1
+fi
+
+failure=0
+
+# Check each file in turn. This is much faster with "dexdump -c", but that
+# was added post-cupcake.
+#
+# The dexdump found in older builds does not stop on checksum failures and
+# will likely crash.
+for file in $files; do
+ echo $file
+ errout=`adb shell "dexdump /data/dalvik-cache/$file > dev/null"`
+ errcount=`echo $errout | wc -w` > /dev/null
+ if [ $errcount != "0" ]; then
+ echo " Failure in $file: $errout"
+ failure=1
+ fi
+done
+
+exit $failure
+
diff --git a/tools/dexdeps/Android.mk b/tools/dexdeps/Android.mk
new file mode 100644
index 0000000..9c2cec7
--- /dev/null
+++ b/tools/dexdeps/Android.mk
@@ -0,0 +1,44 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+# We use copy-file-to-new-target so that the installed
+# script files' timestamps are at least as new as the
+# .jar files they wrap.
+
+# the dexdeps script
+# ============================================================
+include $(CLEAR_VARS)
+LOCAL_IS_HOST_MODULE := true
+LOCAL_MODULE_CLASS := EXECUTABLES
+LOCAL_MODULE := dexdeps
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(HOST_OUT_JAVA_LIBRARIES)/dexdeps$(COMMON_JAVA_PACKAGE_SUFFIX)
+$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/etc/dexdeps | $(ACP)
+ @echo "Copy: $(PRIVATE_MODULE) ($@)"
+ $(copy-file-to-new-target)
+ $(hide) chmod 755 $@
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
+# the other stuff
+# ============================================================
+subdirs := $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
+ src \
+ ))
+
+include $(subdirs)
diff --git a/tools/dexdeps/README.txt b/tools/dexdeps/README.txt
new file mode 100644
index 0000000..14d65b0
--- /dev/null
+++ b/tools/dexdeps/README.txt
@@ -0,0 +1,28 @@
+dexdeps -- DEX external dependency dump
+
+
+This tool dumps a list of fields and methods that a DEX file uses but does
+not define. When combined with a list of public APIs, it can be used to
+determine whether an APK is accessing fields and calling methods that it
+shouldn't be. It may also be useful in determining whether an application
+requires a certain minimum API level to execute.
+
+Basic usage:
+
+ dexdeps [options] <file.{dex,apk,jar}>
+
+For zip archives (including .jar and .apk), dexdeps will look for a
+"classes.dex" entry.
+
+Supported options are:
+
+ --format={brief,xml}
+
+ Specifies the output format.
+
+ "brief" produces one line of output for each field and method. Field
+ and argument types are shown as descriptor strings.
+
+ "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/etc/dexdeps b/tools/dexdeps/etc/dexdeps
new file mode 100644
index 0000000..dc628bd
--- /dev/null
+++ b/tools/dexdeps/etc/dexdeps
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# 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.
+
+# Set up prog to be the path of this script, including following symlinks,
+# and set up progdir to be the fully-qualified pathname of its directory.
+prog="$0"
+while [ -h "${prog}" ]; do
+ newProg=`/bin/ls -ld "${prog}"`
+ newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
+ if expr "x${newProg}" : 'x/' >/dev/null; then
+ prog="${newProg}"
+ else
+ progdir=`dirname "${prog}"`
+ prog="${progdir}/${newProg}"
+ fi
+done
+oldwd=`pwd`
+progdir=`dirname "${prog}"`
+cd "${progdir}"
+progdir=`pwd`
+prog="${progdir}"/`basename "${prog}"`
+cd "${oldwd}"
+
+jarfile=dexdeps.jar
+libdir="$progdir"
+if [ ! -r "$libdir/$jarfile" ]
+then
+ libdir=`dirname "$progdir"`/tools/lib
+fi
+if [ ! -r "$libdir/$jarfile" ]
+then
+ libdir=`dirname "$progdir"`/framework
+fi
+if [ ! -r "$libdir/$jarfile" ]
+then
+ echo `basename "$prog"`": can't find $jarfile"
+ exit 1
+fi
+
+javaOpts=""
+
+# Alternatively, this will extract any parameter "-Jxxx" from the command line
+# and pass them to Java (instead of to dexdeps).
+while expr "x$1" : 'x-J' >/dev/null; do
+ opt=`expr "$1" : '-J\(.*\)'`
+ javaOpts="${javaOpts} -${opt}"
+ shift
+done
+
+if [ "$OSTYPE" = "cygwin" ] ; then
+ jarpath=`cygpath -w "$libdir/$jarfile"`
+else
+ jarpath="$libdir/$jarfile"
+fi
+
+exec java $javaOpts -jar "$jarpath" "$@"
diff --git a/tools/dexdeps/etc/manifest.txt b/tools/dexdeps/etc/manifest.txt
new file mode 100644
index 0000000..7606744
--- /dev/null
+++ b/tools/dexdeps/etc/manifest.txt
@@ -0,0 +1 @@
+Main-Class: com.android.dexdeps.Main
diff --git a/tools/dexdeps/src/Android.mk b/tools/dexdeps/src/Android.mk
new file mode 100644
index 0000000..756a0b3
--- /dev/null
+++ b/tools/dexdeps/src/Android.mk
@@ -0,0 +1,32 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+
+# dexdeps java library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_JAR_MANIFEST := ../etc/manifest.txt
+
+LOCAL_MODULE:= dexdeps
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+INTERNAL_DALVIK_MODULES += $(LOCAL_INSTALLED_MODULE)
+
+include $(BUILD_DROIDDOC)
+
diff --git a/tools/dexdeps/src/com/android/dexdeps/DexData.java b/tools/dexdeps/src/com/android/dexdeps/DexData.java
new file mode 100644
index 0000000..fa79d60
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/DexData.java
@@ -0,0 +1,585 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Arrays;
+
+/**
+ * Data extracted from a DEX file.
+ */
+public class DexData {
+ private RandomAccessFile mDexFile;
+ private HeaderItem mHeaderItem;
+ private String[] mStrings; // strings from string_data_*
+ private TypeIdItem[] mTypeIds;
+ private ProtoIdItem[] mProtoIds;
+ private FieldIdItem[] mFieldIds;
+ private MethodIdItem[] mMethodIds;
+ private ClassDefItem[] mClassDefs;
+
+ private byte tmpBuf[] = new byte[4];
+ private boolean isBigEndian = false;
+
+ /**
+ * Constructs a new DexData for this file.
+ */
+ public DexData(RandomAccessFile raf) {
+ mDexFile = raf;
+ }
+
+ /**
+ * Loads the contents of the DEX file into our data structures.
+ *
+ * @throws IOException if we encounter a problem while reading
+ * @throws DexDataException if the DEX contents look bad
+ */
+ public void load() throws IOException {
+ parseHeaderItem();
+
+ loadStrings();
+ loadTypeIds();
+ loadProtoIds();
+ loadFieldIds();
+ loadMethodIds();
+ loadClassDefs();
+
+ markInternalClasses();
+ }
+
+
+ /**
+ * Parses the interesting bits out of the header.
+ */
+ void parseHeaderItem() throws IOException {
+ mHeaderItem = new HeaderItem();
+
+ seek(0);
+
+ byte[] magic = new byte[8];
+ readBytes(magic);
+ if (!Arrays.equals(magic, HeaderItem.DEX_FILE_MAGIC)) {
+ System.err.println("Magic number is wrong -- are you sure " +
+ "this is a DEX file?");
+ throw new DexDataException();
+ }
+
+ /*
+ * Read the endian tag, so we properly swap things as we read
+ * them from here on.
+ */
+ seek(8+4+20+4+4);
+ mHeaderItem.endianTag = readInt();
+ if (mHeaderItem.endianTag == HeaderItem.ENDIAN_CONSTANT) {
+ /* do nothing */
+ } else if (mHeaderItem.endianTag == HeaderItem.REVERSE_ENDIAN_CONSTANT){
+ /* file is big-endian (!), reverse future reads */
+ isBigEndian = true;
+ } else {
+ System.err.println("Endian constant has unexpected value " +
+ Integer.toHexString(mHeaderItem.endianTag));
+ throw new DexDataException();
+ }
+
+ seek(8+4+20); // magic, checksum, signature
+ mHeaderItem.fileSize = readInt();
+ mHeaderItem.headerSize = readInt();
+ /*mHeaderItem.endianTag =*/ readInt();
+ /*mHeaderItem.linkSize =*/ readInt();
+ /*mHeaderItem.linkOff =*/ readInt();
+ /*mHeaderItem.mapOff =*/ readInt();
+ mHeaderItem.stringIdsSize = readInt();
+ mHeaderItem.stringIdsOff = readInt();
+ mHeaderItem.typeIdsSize = readInt();
+ mHeaderItem.typeIdsOff = readInt();
+ mHeaderItem.protoIdsSize = readInt();
+ mHeaderItem.protoIdsOff = readInt();
+ mHeaderItem.fieldIdsSize = readInt();
+ mHeaderItem.fieldIdsOff = readInt();
+ mHeaderItem.methodIdsSize = readInt();
+ mHeaderItem.methodIdsOff = readInt();
+ mHeaderItem.classDefsSize = readInt();
+ mHeaderItem.classDefsOff = readInt();
+ /*mHeaderItem.dataSize =*/ readInt();
+ /*mHeaderItem.dataOff =*/ readInt();
+ }
+
+ /**
+ * Loads the string table out of the DEX.
+ *
+ * First we read all of the string_id_items, then we read all of the
+ * string_data_item. Doing it this way should allow us to avoid
+ * seeking around in the file.
+ */
+ void loadStrings() throws IOException {
+ int count = mHeaderItem.stringIdsSize;
+ int stringOffsets[] = new int[count];
+
+ //System.out.println("reading " + count + " strings");
+
+ seek(mHeaderItem.stringIdsOff);
+ for (int i = 0; i < count; i++) {
+ stringOffsets[i] = readInt();
+ }
+
+ mStrings = new String[count];
+
+ seek(stringOffsets[0]);
+ for (int i = 0; i < count; i++) {
+ seek(stringOffsets[i]); // should be a no-op
+ mStrings[i] = readString();
+ //System.out.println("STR: " + i + ": " + mStrings[i]);
+ }
+ }
+
+ /**
+ * Loads the type ID list.
+ */
+ void loadTypeIds() throws IOException {
+ int count = mHeaderItem.typeIdsSize;
+ mTypeIds = new TypeIdItem[count];
+
+ //System.out.println("reading " + count + " typeIds");
+ seek(mHeaderItem.typeIdsOff);
+ for (int i = 0; i < count; i++) {
+ mTypeIds[i] = new TypeIdItem();
+ mTypeIds[i].descriptorIdx = readInt();
+
+ //System.out.println(i + ": " + mTypeIds[i].descriptorIdx +
+ // " " + mStrings[mTypeIds[i].descriptorIdx]);
+ }
+ }
+
+ /**
+ * Loads the proto ID list.
+ */
+ void loadProtoIds() throws IOException {
+ int count = mHeaderItem.protoIdsSize;
+ mProtoIds = new ProtoIdItem[count];
+
+ //System.out.println("reading " + count + " protoIds");
+ seek(mHeaderItem.protoIdsOff);
+
+ /*
+ * Read the proto ID items.
+ */
+ for (int i = 0; i < count; i++) {
+ mProtoIds[i] = new ProtoIdItem();
+ mProtoIds[i].shortyIdx = readInt();
+ mProtoIds[i].returnTypeIdx = readInt();
+ mProtoIds[i].parametersOff = readInt();
+
+ //System.out.println(i + ": " + mProtoIds[i].shortyIdx +
+ // " " + mStrings[mProtoIds[i].shortyIdx]);
+ }
+
+ /*
+ * Go back through and read the type lists.
+ */
+ for (int i = 0; i < count; i++) {
+ ProtoIdItem protoId = mProtoIds[i];
+
+ int offset = protoId.parametersOff;
+
+ if (offset == 0) {
+ protoId.types = new int[0];
+ continue;
+ } else {
+ seek(offset);
+ int size = readInt(); // #of entries in list
+ protoId.types = new int[size];
+
+ for (int j = 0; j < size; j++) {
+ protoId.types[j] = readShort() & 0xffff;
+ }
+ }
+ }
+ }
+
+ /**
+ * Loads the field ID list.
+ */
+ void loadFieldIds() throws IOException {
+ int count = mHeaderItem.fieldIdsSize;
+ mFieldIds = new FieldIdItem[count];
+
+ //System.out.println("reading " + count + " fieldIds");
+ seek(mHeaderItem.fieldIdsOff);
+ for (int i = 0; i < count; i++) {
+ mFieldIds[i] = new FieldIdItem();
+ mFieldIds[i].classIdx = readShort() & 0xffff;
+ mFieldIds[i].typeIdx = readShort() & 0xffff;
+ mFieldIds[i].nameIdx = readInt();
+
+ //System.out.println(i + ": " + mFieldIds[i].nameIdx +
+ // " " + mStrings[mFieldIds[i].nameIdx]);
+ }
+ }
+
+ /**
+ * Loads the method ID list.
+ */
+ void loadMethodIds() throws IOException {
+ int count = mHeaderItem.methodIdsSize;
+ mMethodIds = new MethodIdItem[count];
+
+ //System.out.println("reading " + count + " methodIds");
+ seek(mHeaderItem.methodIdsOff);
+ for (int i = 0; i < count; i++) {
+ mMethodIds[i] = new MethodIdItem();
+ mMethodIds[i].classIdx = readShort() & 0xffff;
+ mMethodIds[i].protoIdx = readShort() & 0xffff;
+ mMethodIds[i].nameIdx = readInt();
+
+ //System.out.println(i + ": " + mMethodIds[i].nameIdx +
+ // " " + mStrings[mMethodIds[i].nameIdx]);
+ }
+ }
+
+ /**
+ * Loads the class defs list.
+ */
+ void loadClassDefs() throws IOException {
+ int count = mHeaderItem.classDefsSize;
+ mClassDefs = new ClassDefItem[count];
+
+ //System.out.println("reading " + count + " classDefs");
+ seek(mHeaderItem.classDefsOff);
+ for (int i = 0; i < count; i++) {
+ mClassDefs[i] = new ClassDefItem();
+ mClassDefs[i].classIdx = readInt();
+
+ /* access_flags = */ readInt();
+ /* superclass_idx = */ readInt();
+ /* interfaces_off = */ readInt();
+ /* source_file_idx = */ readInt();
+ /* annotations_off = */ readInt();
+ /* class_data_off = */ readInt();
+ /* static_values_off = */ readInt();
+
+ //System.out.println(i + ": " + mClassDefs[i].classIdx + " " +
+ // mStrings[mTypeIds[mClassDefs[i].classIdx].descriptorIdx]);
+ }
+ }
+
+ /**
+ * Sets the "internal" flag on type IDs which are defined in the
+ * DEX file or within the VM (e.g. primitive classes and arrays).
+ */
+ void markInternalClasses() {
+ for (int i = mClassDefs.length -1; i >= 0; i--) {
+ mTypeIds[mClassDefs[i].classIdx].internal = true;
+ }
+
+ for (int i = 0; i < mTypeIds.length; i++) {
+ String className = mStrings[mTypeIds[i].descriptorIdx];
+
+ if (className.length() == 1) {
+ // primitive class
+ mTypeIds[i].internal = true;
+ } else if (className.charAt(0) == '[') {
+ mTypeIds[i].internal = true;
+ }
+
+ //System.out.println(i + " " +
+ // (mTypeIds[i].internal ? "INTERNAL" : "external") + " - " +
+ // mStrings[mTypeIds[i].descriptorIdx]);
+ }
+ }
+
+
+ /*
+ * =======================================================================
+ * Queries
+ * =======================================================================
+ */
+
+ /**
+ * Returns the class name, given an index into the type_ids table.
+ */
+ private String classNameFromTypeIndex(int idx) {
+ return mStrings[mTypeIds[idx].descriptorIdx];
+ }
+
+ /**
+ * Returns an array of method argument type strings, given an index
+ * into the proto_ids table.
+ */
+ private String[] argArrayFromProtoIndex(int idx) {
+ ProtoIdItem protoId = mProtoIds[idx];
+ String[] result = new String[protoId.types.length];
+
+ for (int i = 0; i < protoId.types.length; i++) {
+ result[i] = mStrings[mTypeIds[protoId.types[i]].descriptorIdx];
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns a string representing the method's return type, given an
+ * index into the proto_ids table.
+ */
+ private String returnTypeFromProtoIndex(int idx) {
+ ProtoIdItem protoId = mProtoIds[idx];
+ return mStrings[mTypeIds[protoId.returnTypeIdx].descriptorIdx];
+ }
+
+ /**
+ * Returns an array with all of the field references that don't
+ * correspond to classes in the DEX file.
+ */
+ public FieldRef[] getExternalFieldReferences() {
+ // get a count
+ int count = 0;
+ for (int i = 0; i < mFieldIds.length; i++) {
+ if (!mTypeIds[mFieldIds[i].classIdx].internal)
+ count++;
+ }
+
+ //System.out.println("count is " + count + " of " + mFieldIds.length);
+
+ FieldRef[] fieldRefs = new FieldRef[count];
+ count = 0;
+ for (int i = 0; i < mFieldIds.length; i++) {
+ if (!mTypeIds[mFieldIds[i].classIdx].internal) {
+ FieldIdItem fieldId = mFieldIds[i];
+ fieldRefs[count++] =
+ new FieldRef(classNameFromTypeIndex(fieldId.classIdx),
+ classNameFromTypeIndex(fieldId.typeIdx),
+ mStrings[fieldId.nameIdx]);
+ }
+ }
+
+ assert count == fieldRefs.length;
+
+ return fieldRefs;
+ }
+
+ /**
+ * Returns an array with all of the method references that don't
+ * correspond to classes in the DEX file.
+ */
+ public MethodRef[] getExternalMethodReferences() {
+ // get a count
+ int count = 0;
+ for (int i = 0; i < mMethodIds.length; i++) {
+ if (!mTypeIds[mMethodIds[i].classIdx].internal)
+ count++;
+ }
+
+ //System.out.println("count is " + count + " of " + mMethodIds.length);
+
+ MethodRef[] methodRefs = new MethodRef[count];
+ count = 0;
+ for (int i = 0; i < mMethodIds.length; i++) {
+ if (!mTypeIds[mMethodIds[i].classIdx].internal) {
+ MethodIdItem methodId = mMethodIds[i];
+ methodRefs[count++] =
+ new MethodRef(classNameFromTypeIndex(methodId.classIdx),
+ argArrayFromProtoIndex(methodId.protoIdx),
+ returnTypeFromProtoIndex(methodId.protoIdx),
+ mStrings[methodId.nameIdx]);
+ }
+ }
+
+ assert count == methodRefs.length;
+
+ return methodRefs;
+ }
+
+
+ /*
+ * =======================================================================
+ * Basic I/O functions
+ * =======================================================================
+ */
+
+ /**
+ * Seeks the DEX file to the specified absolute position.
+ */
+ void seek(int position) throws IOException {
+ mDexFile.seek(position);
+ }
+
+ /**
+ * Fills the buffer by reading bytes from the DEX file.
+ */
+ void readBytes(byte[] buffer) throws IOException {
+ mDexFile.readFully(buffer);
+ }
+
+ /**
+ * Reads a single signed byte value.
+ */
+ byte readByte() throws IOException {
+ mDexFile.readFully(tmpBuf, 0, 1);
+ return tmpBuf[0];
+ }
+
+ /**
+ * Reads a signed 16-bit integer, byte-swapping if necessary.
+ */
+ short readShort() throws IOException {
+ mDexFile.readFully(tmpBuf, 0, 2);
+ if (isBigEndian) {
+ return (short) ((tmpBuf[1] & 0xff) | ((tmpBuf[0] & 0xff) << 8));
+ } else {
+ return (short) ((tmpBuf[0] & 0xff) | ((tmpBuf[1] & 0xff) << 8));
+ }
+ }
+
+ /**
+ * Reads a signed 32-bit integer, byte-swapping if necessary.
+ */
+ int readInt() throws IOException {
+ mDexFile.readFully(tmpBuf, 0, 4);
+
+ if (isBigEndian) {
+ return (tmpBuf[3] & 0xff) | ((tmpBuf[2] & 0xff) << 8) |
+ ((tmpBuf[1] & 0xff) << 16) | ((tmpBuf[0] & 0xff) << 24);
+ } else {
+ return (tmpBuf[0] & 0xff) | ((tmpBuf[1] & 0xff) << 8) |
+ ((tmpBuf[2] & 0xff) << 16) | ((tmpBuf[3] & 0xff) << 24);
+ }
+ }
+
+ /**
+ * Reads a variable-length unsigned LEB128 value. Does not attempt to
+ * verify that the value is valid.
+ *
+ * @throws EOFException if we run off the end of the file
+ */
+ int readUnsignedLeb128() throws IOException {
+ int result = 0;
+ byte val;
+
+ do {
+ val = readByte();
+ result = (result << 7) | (val & 0x7f);
+ } while (val < 0);
+
+ return result;
+ }
+
+ /**
+ * Reads a UTF-8 string.
+ *
+ * We don't know how long the UTF-8 string is, so we have to read one
+ * byte at a time. We could make an educated guess based on the
+ * utf16_size and seek back if we get it wrong, but seeking backward
+ * may cause the underlying implementation to reload I/O buffers.
+ */
+ String readString() throws IOException {
+ int utf16len = readUnsignedLeb128();
+ byte inBuf[] = new byte[utf16len * 3]; // worst case
+ int idx;
+
+ for (idx = 0; idx < inBuf.length; idx++) {
+ byte val = readByte();
+ if (val == 0)
+ break;
+ inBuf[idx] = val;
+ }
+
+ return new String(inBuf, 0, idx, "UTF-8");
+ }
+
+
+ /*
+ * =======================================================================
+ * Internal "structure" declarations
+ * =======================================================================
+ */
+
+ /**
+ * Holds the contents of a header_item.
+ */
+ static class HeaderItem {
+ public int fileSize;
+ public int headerSize;
+ public int endianTag;
+ public int stringIdsSize, stringIdsOff;
+ public int typeIdsSize, typeIdsOff;
+ public int protoIdsSize, protoIdsOff;
+ public int fieldIdsSize, fieldIdsOff;
+ public int methodIdsSize, methodIdsOff;
+ public int classDefsSize, classDefsOff;
+
+ /* expected magic values */
+ public static final byte[] DEX_FILE_MAGIC = {
+ 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
+ public static final int ENDIAN_CONSTANT = 0x12345678;
+ public static final int REVERSE_ENDIAN_CONSTANT = 0x78563412;
+ }
+
+ /**
+ * Holds the contents of a type_id_item.
+ *
+ * This is chiefly a list of indices into the string table. We need
+ * some additional bits of data, such as whether or not the type ID
+ * represents a class defined in this DEX, so we use an object for
+ * each instead of a simple integer. (Could use a parallel array, but
+ * since this is a desktop app it's not essential.)
+ */
+ static class TypeIdItem {
+ public int descriptorIdx; // index into string_ids
+
+ public boolean internal; // defined within this DEX file?
+ }
+
+ /**
+ * Holds the contents of a proto_id_item.
+ */
+ static class ProtoIdItem {
+ public int shortyIdx; // index into string_ids
+ public int returnTypeIdx; // index into type_ids
+ public int parametersOff; // file offset to a type_list
+
+ public int types[]; // contents of type list
+ }
+
+ /**
+ * Holds the contents of a field_id_item.
+ */
+ static class FieldIdItem {
+ public int classIdx; // index into type_ids (defining class)
+ public int typeIdx; // index into type_ids (field type)
+ public int nameIdx; // index into string_ids
+ }
+
+ /**
+ * Holds the contents of a method_id_item.
+ */
+ static class MethodIdItem {
+ public int classIdx; // index into type_ids
+ public int protoIdx; // index into proto_ids
+ public int nameIdx; // index into string_ids
+ }
+
+ /**
+ * Holds the contents of a class_def_item.
+ *
+ * We don't really need a class for this, but there's some stuff in
+ * the class_def_item that we might want later.
+ */
+ static class ClassDefItem {
+ 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
new file mode 100644
index 0000000..e51853f
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/DexDataException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+/**
+ * Bad data found inside a DEX file.
+ */
+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
new file mode 100644
index 0000000..2726a7a
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/FieldRef.java
@@ -0,0 +1,52 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+public class FieldRef {
+ private String mDeclClass, mFieldType, mFieldName;
+
+ /**
+ * Initializes a new field reference.
+ */
+ public FieldRef(String declClass, String fieldType, String fieldName) {
+ mDeclClass = declClass;
+ mFieldType = fieldType;
+ mFieldName = fieldName;
+ }
+
+ /**
+ * Gets the name of the field's declaring class.
+ */
+ public String getDeclClassName() {
+ return mDeclClass;
+ }
+
+ /**
+ * Gets the type name. Examples: "Ljava/lang/String;", "[I".
+ */
+ public String getTypeName() {
+ return mFieldType;
+ }
+
+ /**
+ * Gets the field name.
+ */
+ public String getName() {
+ return mFieldName;
+ }
+}
+
diff --git a/tools/dexdeps/src/com/android/dexdeps/Main.java b/tools/dexdeps/src/com/android/dexdeps/Main.java
new file mode 100644
index 0000000..7eba3aa
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/Main.java
@@ -0,0 +1,201 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.RandomAccessFile;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+
+public class Main {
+ private static final String CLASSES_DEX = "classes.dex";
+
+ private String mInputFileName;
+ private String mOutputFormat = "brief";
+
+ /**
+ * Entry point.
+ */
+ public static void main(String[] args) {
+ Main main = new Main();
+ main.run(args);
+ }
+
+ /**
+ * Start things up.
+ */
+ void run(String[] args) {
+ try {
+ parseArgs(args);
+ RandomAccessFile raf = openInputFile();
+ DexData dexData = new DexData(raf);
+ dexData.load();
+
+ Output.generate(dexData, mOutputFormat);
+ } catch (UsageException ue) {
+ usage();
+ System.exit(2);
+ } catch (IOException ioe) {
+ if (ioe.getMessage() != null)
+ System.err.println("Failed: " + ioe);
+ System.exit(1);
+ } catch (DexDataException dde) {
+ /* a message was already reported, just bail quietly */
+ System.exit(1);
+ }
+ }
+
+ /**
+ * Opens the input file, which could be a .dex or a .jar/.apk with a
+ * classes.dex inside. If the latter, we extract the contents to a
+ * temporary file.
+ */
+ RandomAccessFile openInputFile() throws IOException {
+ RandomAccessFile raf;
+
+ raf = openInputFileAsZip();
+ if (raf == null) {
+ File inputFile = new File(mInputFileName);
+ raf = new RandomAccessFile(inputFile, "r");
+ }
+
+ return raf;
+ }
+
+ /**
+ * Tries to open the input file as a Zip archive (jar/apk) with a
+ * "classes.dex" inside.
+ *
+ * @return a RandomAccessFile for classes.dex, or null if the input file
+ * is not a zip archive
+ * @throws IOException if the file isn't found, or it's a zip and
+ * classes.dex isn't found inside
+ */
+ RandomAccessFile openInputFileAsZip() throws IOException {
+ ZipFile zipFile;
+
+ /*
+ * Try it as a zip file.
+ */
+ try {
+ zipFile = new ZipFile(mInputFileName);
+ } catch (FileNotFoundException fnfe) {
+ /* not found, no point in retrying as non-zip */
+ System.err.println("Unable to open '" + mInputFileName + "': " +
+ fnfe.getMessage());
+ throw fnfe;
+ } catch (ZipException ze) {
+ /* not a zip */
+ return null;
+ }
+
+ /*
+ * We know it's a zip; see if there's anything useful inside. A
+ * failure here results in some type of IOException (of which
+ * ZipException is a subclass).
+ */
+ ZipEntry entry = zipFile.getEntry(CLASSES_DEX);
+ if (entry == null) {
+ System.err.println("Unable to find '" + CLASSES_DEX +
+ "' in '" + mInputFileName + "'");
+ zipFile.close();
+ throw new ZipException();
+ }
+
+ InputStream zis = zipFile.getInputStream(entry);
+
+ /*
+ * Create a temp file to hold the DEX data, open it, and delete it
+ * to ensure it doesn't hang around if we fail.
+ */
+ File tempFile = File.createTempFile("dexdeps", ".dex");
+ //System.out.println("+++ using temp " + tempFile);
+ RandomAccessFile raf = new RandomAccessFile(tempFile, "rw");
+ tempFile.delete();
+
+ /*
+ * Copy all data from input stream to output file.
+ */
+ byte copyBuf[] = new byte[32768];
+ int actual;
+
+ while (true) {
+ actual = zis.read(copyBuf);
+ if (actual == -1)
+ break;
+
+ raf.write(copyBuf, 0, actual);
+ }
+
+ zis.close();
+ raf.seek(0);
+
+ return raf;
+ }
+
+
+ /**
+ * Parses command-line arguments.
+ *
+ * @throws UsageException if arguments are missing or poorly formed
+ */
+ void parseArgs(String[] args) {
+ int idx;
+
+ for (idx = 0; idx < args.length; idx++) {
+ String arg = args[idx];
+
+ if (arg.equals("--") || !arg.startsWith("--")) {
+ break;
+ } else if (arg.startsWith("--format=")) {
+ mOutputFormat = arg.substring(arg.indexOf('=') + 1);
+ if (!mOutputFormat.equals("brief") &&
+ !mOutputFormat.equals("xml"))
+ {
+ System.err.println("Unknown format '" + mOutputFormat +"'");
+ throw new UsageException();
+ }
+ //System.out.println("+++ using format " + mOutputFormat);
+ } else {
+ System.err.println("Unknown option '" + arg + "'");
+ throw new UsageException();
+ }
+ }
+
+ // expecting one argument left
+ if (idx != args.length - 1) {
+ throw new UsageException();
+ }
+
+ mInputFileName = args[idx];
+ }
+
+ /**
+ * Prints command-line usage info.
+ */
+ void usage() {
+ System.err.println("\nUsage: dexdeps [options] <file.{dex,apk,jar}>");
+ System.err.println("Options:");
+ System.err.println(" --format={brief,xml}");
+ }
+}
+
diff --git a/tools/dexdeps/src/com/android/dexdeps/MethodRef.java b/tools/dexdeps/src/com/android/dexdeps/MethodRef.java
new file mode 100644
index 0000000..96522eb
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/MethodRef.java
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+public class MethodRef {
+ private String mDeclClass, mReturnType, mMethodName;
+ private String[] mArgTypes;
+
+ /**
+ * Initializes a new field reference.
+ */
+ public MethodRef(String declClass, String[] argTypes, String returnType,
+ String methodName) {
+ mDeclClass = declClass;
+ mArgTypes = argTypes;
+ mReturnType = returnType;
+ mMethodName = methodName;
+ }
+
+ /**
+ * Gets the name of the method's declaring class.
+ */
+ public String getDeclClassName() {
+ return mDeclClass;
+ }
+
+ /**
+ * Gets the method's descriptor.
+ */
+ public String getDescriptor() {
+ return descriptorFromProtoArray(mArgTypes, mReturnType);
+ }
+
+ /**
+ * Gets the method's name.
+ */
+ public String getName() {
+ return mMethodName;
+ }
+
+ /**
+ * Gets an array of method argument types.
+ */
+ public String[] getArgumentTypeNames() {
+ return mArgTypes;
+ }
+
+ /**
+ * Gets the method's return type. Examples: "Ljava/lang/String;", "[I".
+ */
+ public String getReturnTypeName() {
+ return mReturnType;
+ }
+
+ /**
+ * Returns the method descriptor, given the argument and return type
+ * prototype strings.
+ */
+ private static String descriptorFromProtoArray(String[] protos,
+ String returnType) {
+ StringBuilder builder = new StringBuilder();
+
+ builder.append("(");
+ for (int i = 0; i < protos.length; i++) {
+ builder.append(protos[i]);
+ }
+
+ builder.append(")");
+ builder.append(returnType);
+
+ return builder.toString();
+ }
+}
+
diff --git a/tools/dexdeps/src/com/android/dexdeps/Output.java b/tools/dexdeps/src/com/android/dexdeps/Output.java
new file mode 100644
index 0000000..0039b33
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/Output.java
@@ -0,0 +1,264 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+/**
+ * Generate fancy output.
+ */
+public class Output {
+ public static void generate(DexData dexData, String format) {
+ if (format.equals("brief")) {
+ printBrief(dexData);
+ } else if (format.equals("xml")) {
+ printXml(dexData);
+ } else {
+ /* should've been trapped in arg handler */
+ throw new RuntimeException("unknown output format");
+ }
+ }
+
+ /**
+ * Prints the data in a simple human-readable format.
+ */
+ static void printBrief(DexData dexData) {
+ FieldRef[] externFieldRefs = dexData.getExternalFieldReferences();
+ MethodRef[] externMethodRefs = dexData.getExternalMethodReferences();
+
+ printFieldRefs(externFieldRefs);
+ printMethodRefs(externMethodRefs);
+ }
+
+ /**
+ * Prints the list of fields in a simple human-readable format.
+ */
+ static void printFieldRefs(FieldRef[] fields) {
+ System.out.println("Fields:");
+ for (int i = 0; i < fields.length; i++) {
+ FieldRef ref = fields[i];
+
+ System.out.println(descriptorToDot(ref.getDeclClassName()) + "." +
+ ref.getName() + " : " + ref.getTypeName());
+ }
+ }
+
+ /**
+ * Prints the list of methods in a simple human-readable format.
+ */
+ static void printMethodRefs(MethodRef[] methods) {
+ System.out.println("Methods:");
+ for (int i = 0; i < methods.length; i++) {
+ MethodRef ref = methods[i];
+
+ System.out.println(descriptorToDot(ref.getDeclClassName()) +
+ "." + ref.getName() + " : " + ref.getDescriptor());
+ }
+ }
+
+
+ /**
+ * Prints the output in XML format.
+ *
+ * We shouldn't need to XML-escape the field/method info.
+ */
+ static void printXml(DexData dexData) {
+ final String IN0 = "";
+ final String IN1 = " ";
+ final String IN2 = " ";
+ final String IN3 = " ";
+ FieldRef[] externFieldRefs = dexData.getExternalFieldReferences();
+ MethodRef[] externMethodRefs = dexData.getExternalMethodReferences();
+ String prevClass = null;
+
+ System.out.println(IN0 + "<external>");
+
+ /* print fields */
+ for (int i = 0; i < externFieldRefs.length; i++) {
+ FieldRef fref = externFieldRefs[i];
+ String declClassName = fref.getDeclClassName();
+
+ if (prevClass != null && !prevClass.equals(declClassName)) {
+ System.out.println(IN1 + "</class>");
+ }
+ if (!declClassName.equals(prevClass)) {
+ String className = classNameOnly(declClassName);
+ String packageName = packageNameOnly(declClassName);
+ System.out.println(IN1 + "<class package=\"" + packageName +
+ "\" name=\"" + className + "\">");
+ prevClass = declClassName;
+ }
+
+ System.out.println(IN2 + "<field name=\"" + fref.getName() +
+ "\" type=\"" + descriptorToDot(fref.getTypeName()) + "\"/>");
+ }
+
+ /* print methods */
+ for (int i = 0; i < externMethodRefs.length; i++) {
+ MethodRef mref = externMethodRefs[i];
+ String declClassName = mref.getDeclClassName();
+ boolean constructor;
+
+ if (prevClass != null && !prevClass.equals(declClassName)) {
+ System.out.println(IN1 + "</class>");
+ }
+ if (!declClassName.equals(prevClass)) {
+ String className = classNameOnly(declClassName);
+ String packageName = packageNameOnly(declClassName);
+ System.out.println(IN1 + "<class package=\"" + packageName +
+ "\" name=\"" + className + "\">");
+ prevClass = declClassName;
+ }
+
+ constructor = mref.getName().equals("<init>");
+ if (constructor) {
+ /* use class name instead of method name */
+ System.out.println(IN2 + "<constructor name=\"" +
+ classNameOnly(declClassName) + "\" return=\"" +
+ descriptorToDot(mref.getReturnTypeName()) + "\">");
+ } else {
+ System.out.println(IN2 + "<method name=\"" + mref.getName() +
+ "\" return=\"" + descriptorToDot(mref.getReturnTypeName()) +
+ "\">");
+ }
+ String[] args = mref.getArgumentTypeNames();
+ for (int j = 0; j < args.length; j++) {
+ System.out.println(IN3 + "<parameter type=\"" +
+ descriptorToDot(args[j]) + "\"/>");
+ }
+ if (constructor) {
+ System.out.println(IN2 + "</constructor>");
+ } else {
+ System.out.println(IN2 + "</method>");
+ }
+ }
+
+ if (prevClass != null)
+ System.out.println(IN1 + "</class>");
+ System.out.println(IN0 + "</external>");
+ }
+
+
+ /*
+ * =======================================================================
+ * Utility functions
+ * =======================================================================
+ */
+
+ /**
+ * Converts a single-character primitive type into its human-readable
+ * equivalent.
+ */
+ static String primitiveTypeLabel(char typeChar) {
+ /* primitive type; substitute human-readable name in */
+ switch (typeChar) {
+ case 'B': return "byte";
+ case 'C': return "char";
+ case 'D': return "double";
+ case 'F': return "float";
+ case 'I': return "int";
+ case 'J': return "long";
+ case 'S': return "short";
+ case 'V': return "void";
+ case 'Z': return "boolean";
+ default:
+ /* huh? */
+ System.err.println("Unexpected class char " + typeChar);
+ assert false;
+ return "UNKNOWN";
+ }
+ }
+
+ /**
+ * Converts a type descriptor to human-readable "dotted" form. For
+ * example, "Ljava/lang/String;" becomes "java.lang.String", and
+ * "[I" becomes "int[].
+ */
+ static String descriptorToDot(String descr) {
+ int targetLen = descr.length();
+ int offset = 0;
+ int arrayDepth = 0;
+
+ /* strip leading [s; will be added to end */
+ while (targetLen > 1 && descr.charAt(offset) == '[') {
+ offset++;
+ targetLen--;
+ }
+ arrayDepth = offset;
+
+ if (targetLen == 1) {
+ descr = primitiveTypeLabel(descr.charAt(offset));
+ offset = 0;
+ targetLen = descr.length();
+ } else {
+ /* account for leading 'L' and trailing ';' */
+ if (targetLen >= 2 && descr.charAt(offset) == 'L' &&
+ descr.charAt(offset+targetLen-1) == ';')
+ {
+ targetLen -= 2; /* two fewer chars to copy */
+ offset++; /* skip the 'L' */
+ }
+ }
+
+ char[] buf = new char[targetLen + arrayDepth * 2];
+
+ /* copy class name over */
+ int i;
+ for (i = 0; i < targetLen; i++) {
+ char ch = descr.charAt(offset + i);
+ buf[i] = (ch == '/') ? '.' : ch;
+ }
+
+ /* add the appopriate number of brackets for arrays */
+ while (arrayDepth-- > 0) {
+ buf[i++] = '[';
+ buf[i++] = ']';
+ }
+ assert i == buf.length;
+
+ return new String(buf);
+ }
+
+ /**
+ * Extracts the class name from a type descriptor.
+ */
+ static String classNameOnly(String typeName) {
+ String dotted = descriptorToDot(typeName);
+
+ int start = dotted.lastIndexOf(".");
+ if (start < 0) {
+ return dotted;
+ } else {
+ return dotted.substring(start+1);
+ }
+ }
+
+ /**
+ * Extracts the package name from a type descriptor, and returns it in
+ * dotted form.
+ */
+ static String packageNameOnly(String typeName) {
+ String dotted = descriptorToDot(typeName);
+
+ int end = dotted.lastIndexOf(".");
+ if (end < 0) {
+ /* lives in default package */
+ return "";
+ } else {
+ return dotted.substring(0, end);
+ }
+ }
+}
+
diff --git a/tools/dexdeps/src/com/android/dexdeps/UsageException.java b/tools/dexdeps/src/com/android/dexdeps/UsageException.java
new file mode 100644
index 0000000..f9f971b
--- /dev/null
+++ b/tools/dexdeps/src/com/android/dexdeps/UsageException.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+package com.android.dexdeps;
+
+/**
+ * Tells the main entry point to show the usage information and bail.
+ */
+public class UsageException extends RuntimeException {
+}
+
diff --git a/tools/gclog.py b/tools/gclog.py
new file mode 100755
index 0000000..4696965
--- /dev/null
+++ b/tools/gclog.py
@@ -0,0 +1,204 @@
+#!/usr/bin/env python
+#
+# 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.
+
+#
+# Version 1.0, 29-Apr-2009
+#
+# Parse event log output, looking for GC events. Format them for human
+# consumption.
+#
+# ALL OUTPUT VALUES ARE APPROXIMATE. The event log data format uses a
+# 12-bit floating-point representation, which means there aren't enough
+# bits to accurately represent anything but small integers. Larger
+# values will be rounded off.
+#
+# The data is generated by dalvik/vm/alloc/HeapDebug.c.
+#
+
+import os
+import re
+import time
+
+def unfloat12(f12):
+ """Unpack a float12 value"""
+ if f12 < 0:
+ raise DataParseError, "bad float12 value %s" % f12
+ return (f12 & 0x1ff) << ((f12 >> 9) * 4)
+
+
+def parseGlobalInfo(value):
+ """Parse event0 (global info)"""
+ value = int(value)
+
+ # Global information:
+ #
+ # [63 ] Must be zero
+ # [62-24] ASCII process identifier
+ # [23-12] GC time in ms
+ # [11- 0] Bytes freed
+ id = (value >> 24) & 0xffffffffff
+ gctime = unfloat12((value >> 12) & 0xfff)
+ bytes_freed = unfloat12(value & 0xfff)
+
+ idstr = "%c%c%c%c%c" % ( \
+ (id >> 32) & 0xff, \
+ (id >> 24) & 0xff, \
+ (id >> 16) & 0xff, \
+ (id >> 8) & 0xff, \
+ id & 0xff )
+
+ return ( idstr, gctime, bytes_freed )
+
+
+def parseAggHeapStats(value):
+ """Parse event1 (aggregated heap stats)"""
+ value = int(value)
+
+ # Aggregated heap stats:
+ #
+ # [63-62] 10
+ # [61-60] Reserved; must be zero
+ # [59-48] Objects freed
+ # [47-36] Actual size (current footprint)
+ # [35-24] Allowed size (current hard max)
+ # [23-12] Objects allocated
+ # [11- 0] Bytes allocated
+ freed = unfloat12((value >> 48) & 0xfff)
+ footprint = unfloat12((value >> 36) & 0xfff)
+ allowed = unfloat12((value >> 24) & 0xfff)
+ objs = unfloat12((value >> 12) & 0xfff)
+ bytes = unfloat12(value & 0xfff)
+
+ return ( freed, footprint, allowed, objs, bytes )
+
+
+def parseZygoteStats(value):
+ """Parse event2 (zygote heap stats)"""
+ value = int(value)
+
+ # Zygote heap stats (except for the soft limit, which belongs to the
+ # active heap):
+ #
+ # [63-62] 11
+ # [61-60] Reserved; must be zero
+ # [59-48] Soft Limit (for the active heap)
+ # [47-36] Actual size (current footprint)
+ # [35-24] Allowed size (current hard max)
+ # [23-12] Objects allocated
+ # [11- 0] Bytes allocated
+ soft_limit = unfloat12((value >> 48) & 0xfff)
+ actual = unfloat12((value >> 36) & 0xfff)
+ allowed = unfloat12((value >> 24) & 0xfff)
+ objs = unfloat12((value >> 12) & 0xfff)
+ bytes = unfloat12(value & 0xfff)
+
+ return ( soft_limit, actual, allowed, objs, bytes )
+
+
+def parseExternalStats(value):
+ """Parse event3 (external allocation stats)"""
+ value = int(value)
+
+ # Report the current external allocation stats and the native heap
+ # summary.
+ #
+ # [63-48] Reserved; must be zero (TODO: put new data in these slots)
+ # [47-36] dlmalloc_footprint
+ # [35-24] mallinfo: total allocated space
+ # [23-12] External byte limit
+ # [11- 0] External bytes allocated
+ footprint = unfloat12((value >> 36) & 0xfff) # currently disabled
+ total = unfloat12((value >> 24) & 0xfff) # currently disabled
+ limit = unfloat12((value >> 12) & 0xfff)
+ bytes = unfloat12(value & 0xfff)
+
+ return ( footprint, total, limit, bytes )
+
+
+def handleGcInfo(timestamp, pid, values):
+ """Handle a single dvm_gc_info event"""
+
+ pid = int(pid)
+
+ global_info = parseGlobalInfo(values[0])
+ heap_stats = parseAggHeapStats(values[1])
+ zygote = parseZygoteStats(values[2])
+ external = parseExternalStats(values[3])
+
+ debug = False
+ if debug:
+ print "RAW: %s %s (%s,%s,%s,%s)" % \
+ (timestamp, pid, values[0], values[1], values[2], values[3])
+
+ print "> id=\"%s\" time=%d freed=%d" % (global_info[0], global_info[1], global_info[2])
+ print "> freed=%d foot=%d allow=%d objs=%d bytes=%d" % \
+ (heap_stats[0], heap_stats[1], heap_stats[2], heap_stats[3], heap_stats[4])
+ print "> soft=%d act=%d allow=%d objs=%d bytes=%d" % \
+ (zygote[0], zygote[1], zygote[2], zygote[3], zygote[4])
+ print "> foot=%d total=%d limit=%d alloc=%d" % \
+ (external[0], external[1], external[2], external[3])
+
+ print "%s %s(%d) softlim=%dKB, extlim=%dKB, extalloc=%dKB" % \
+ (timestamp, global_info[0], pid, zygote[0]/1024, external[2]/1024, external[3]/1024)
+ print " freed %d objects / %d bytes in %dms" % \
+ (heap_stats[0], global_info[2], global_info[1])
+
+
+def filterInput(logPipe):
+ """Loop until EOF, pulling out GC events"""
+
+ # 04-29 20:31:00.334 I/dvm_gc_info( 69): [8320808730292729543,-8916699241518090181,-4006371297196337158,8165229]
+ gc_info_re = re.compile(r"""
+ (\d+-\d+\ \d+:\d+:\d+)\.\d+ # extract the date (#1), ignoring ms
+ .* # filler, usually " I/"
+ dvm_gc_info # only interested in GC info lines
+ \(\s*(\d+)\) # extract the pid (#2)
+ :\ \[ # filler
+ ([0-9-]+),([0-9-]+),([0-9-]+),([0-9-]+) # four values, may be negative
+ \].* # junk to end of line
+ """, re.VERBOSE)
+
+ while True:
+ line = logPipe.readline()
+ if not line:
+ print "EOF hit"
+ return
+
+ match = gc_info_re.match(line)
+ if not match:
+ #print "no match on %s" % line.strip()
+ continue
+ else:
+ handleGcInfo(match.group(1), match.group(2), ( match.group(3), \
+ match.group(4), match.group(5), match.group(6) ) )
+
+def start():
+ """Entry point"""
+
+ # launch a logcat and read from it
+ command = 'adb logcat -v time -b events'
+ logPipe = os.popen(command)
+
+ try:
+ filterInput(logPipe)
+ except KeyboardInterrupt, err:
+ print "Stopping on keyboard interrupt."
+
+ logPipe.close()
+
+
+start()
+
diff --git a/vm/Android.mk b/vm/Android.mk
index f3eed3f..5b6e0ed 100644
--- a/vm/Android.mk
+++ b/vm/Android.mk
@@ -59,9 +59,11 @@
# - LOGV
# - assert() (NDEBUG is handled in the build system)
#
- LOCAL_CFLAGS += -DWITH_INSTR_CHECKS -DWITH_EXTRA_OBJECT_VALIDATION
+ LOCAL_CFLAGS += -DWITH_INSTR_CHECKS
+ LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION
LOCAL_CFLAGS += -DWITH_TRACKREF_CHECKS
LOCAL_CFLAGS += -DWITH_ALLOC_LIMITS
+ LOCAL_CFLAGS += -DWITH_EXTRA_GC_CHECKS=1
#LOCAL_CFLAGS += -DCHECK_MUTEX
#LOCAL_CFLAGS += -DPROFILE_FIELD_ACCESS
LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=3
@@ -77,6 +79,8 @@
#LOCAL_CFLAGS += -DNDEBUG -DLOG_NDEBUG=1
# "-O2" is redundant for device (release) but useful for sim (debug)
#LOCAL_CFLAGS += -O2 -Winline
+ #LOCAL_CFLAGS += -DWITH_EXTRA_OBJECT_VALIDATION
+ LOCAL_CFLAGS += -DWITH_EXTRA_GC_CHECKS=1
LOCAL_CFLAGS += -DDVM_SHOW_EXCEPTION=1
# if you want to try with assertions on the device, add:
#LOCAL_CFLAGS += -UNDEBUG -DDEBUG=1 -DLOG_NDEBUG=1 -DWITH_DALVIK_ASSERT
@@ -177,8 +181,26 @@
reflect/Annotation.c \
reflect/Proxy.c \
reflect/Reflect.c \
+ test/AtomicSpeed.c \
test/TestHash.c
+ifeq ($(WITH_JIT_TUNING),true)
+ LOCAL_CFLAGS += -DWITH_JIT_TUNING
+endif
+
+ifeq ($(WITH_JIT),true)
+ # NOTE: Turn on assertion for JIT for now
+ LOCAL_CFLAGS += -DWITH_DALVIK_ASSERT
+ LOCAL_CFLAGS += -DWITH_JIT
+ LOCAL_SRC_FILES += \
+ ../dexdump/OpCodeNames.c \
+ compiler/Compiler.c \
+ compiler/Frontend.c \
+ compiler/Utility.c \
+ compiler/IntermediateRep.c \
+ interp/Jit.c
+endif
+
WITH_HPROF := $(strip $(WITH_HPROF))
ifeq ($(WITH_HPROF),)
WITH_HPROF := true
@@ -226,36 +248,51 @@
LOCAL_SHARED_LIBRARIES += libdl
endif
+MTERP_ARCH_KNOWN := false
+
ifeq ($(TARGET_ARCH),arm)
+ #TARGET_ARCH_VARIANT := armv7-a
+ #LOCAL_CFLAGS += -march=armv7-a -mfloat-abi=softfp -mfpu=vfp
+ MTERP_ARCH_KNOWN := true
+ # Select architecture-specific sources (armv4t, armv5te etc.)
LOCAL_SRC_FILES += \
arch/arm/CallOldABI.S \
arch/arm/CallEABI.S \
- arch/arm/HintsEABI.c
- # TODO: select sources for ARMv4 vs. ARMv5TE
+ arch/arm/HintsEABI.c \
+ mterp/out/InterpC-$(TARGET_ARCH_VARIANT).c.arm \
+ mterp/out/InterpAsm-$(TARGET_ARCH_VARIANT).S
+
+ ifeq ($(WITH_JIT),true)
+ LOCAL_SRC_FILES += \
+ compiler/codegen/armv5te/Codegen.c \
+ compiler/codegen/armv5te/Assemble.c \
+ compiler/codegen/armv5te/ArchUtility.c \
+ compiler/codegen/armv5te/FpCodegen-$(TARGET_ARCH_VARIANT).c \
+ compiler/codegen/armv5te/LocalOptimizations.c \
+ compiler/codegen/armv5te/GlobalOptimizations.c \
+ compiler/template/out/CompilerTemplateAsm-armv5te.S
+ endif
+endif
+
+ifeq ($(TARGET_ARCH),x86)
+ MTERP_ARCH_KNOWN := true
LOCAL_SRC_FILES += \
- mterp/out/InterpC-armv5te.c.arm \
- mterp/out/InterpAsm-armv5te.S
- LOCAL_SHARED_LIBRARIES += libdl
-else
- ifeq ($(TARGET_ARCH),x86)
- LOCAL_SRC_FILES += \
arch/x86/Call386ABI.S \
- arch/x86/Hints386ABI.c
- LOCAL_SRC_FILES += \
+ arch/x86/Hints386ABI.c \
mterp/out/InterpC-x86.c \
mterp/out/InterpAsm-x86.S
- else
- # unknown architecture, try to use FFI
- LOCAL_C_INCLUDES += external/libffi/$(TARGET_OS)-$(TARGET_ARCH)
- LOCAL_SRC_FILES += \
+endif
+
+ifeq ($(MTERP_ARCH_KNOWN),false)
+ # unknown architecture, try to use FFI
+ LOCAL_C_INCLUDES += external/libffi/$(TARGET_OS)-$(TARGET_ARCH)
+ LOCAL_SHARED_LIBRARIES += libffi
+
+ LOCAL_SRC_FILES += \
arch/generic/Call.c \
- arch/generic/Hints.c
- LOCAL_SHARED_LIBRARIES += libffi
-
- LOCAL_SRC_FILES += \
+ arch/generic/Hints.c \
mterp/out/InterpC-allstubs.c \
mterp/out/InterpAsm-allstubs.S
- endif
endif
diff --git a/vm/CheckJni.c b/vm/CheckJni.c
index 0601e72..cece49a 100644
--- a/vm/CheckJni.c
+++ b/vm/CheckJni.c
@@ -35,6 +35,116 @@
#include <zlib.h>
+static void abortMaybe(void); // fwd
+
+
+/*
+ * ===========================================================================
+ * JNI call bridge wrapper
+ * ===========================================================================
+ */
+
+/*
+ * Check the result of a native method call that returns an object reference.
+ *
+ * The primary goal here is to verify that native code is returning the
+ * correct type of object. If it's declared to return a String but actually
+ * returns a byte array, things will fail in strange ways later on.
+ *
+ * This can be a fairly expensive operation, since we have to look up the
+ * return type class by name in method->clazz' class loader. We take a
+ * shortcut here and allow the call to succeed if the descriptor strings
+ * match. This will allow some false-positives when a class is redefined
+ * by a class loader, but that's rare enough that it doesn't seem worth
+ * testing for.
+ */
+static void checkCallCommon(const u4* args, JValue* pResult,
+ const Method* method, Thread* self)
+{
+ assert(pResult->l != NULL);
+ ClassObject* objClazz = ((Object*)pResult->l)->clazz;
+
+ /*
+ * Make sure that pResult->l is an instance of the type this
+ * method was expected to return.
+ */
+ const char* declType = dexProtoGetReturnType(&method->prototype);
+ const char* objType = objClazz->descriptor;
+ if (strcmp(declType, objType) == 0) {
+ /* names match; ignore class loader issues and allow it */
+ LOGV("Check %s.%s: %s io %s (FAST-OK)\n",
+ method->clazz->descriptor, method->name, objType, declType);
+ } else {
+ /*
+ * Names didn't match. We need to resolve declType in the context
+ * of method->clazz->classLoader, and compare the class objects
+ * for equality.
+ *
+ * Since we're returning an instance of declType, it's safe to
+ * assume that it has been loaded and initialized (or, for the case
+ * of an array, generated), so we can just look for it in the
+ * loaded-classes list.
+ */
+ ClassObject* declClazz;
+
+ declClazz = dvmLookupClass(declType, method->clazz->classLoader, false);
+ if (declClazz == NULL) {
+ LOGW("JNI WARNING: method declared to return '%s' returned '%s'\n",
+ declType, objType);
+ LOGW(" failed in %s.%s ('%s' not found)\n",
+ method->clazz->descriptor, method->name, declType);
+ abortMaybe();
+ return;
+ }
+ if (!dvmInstanceof(objClazz, declClazz)) {
+ LOGW("JNI WARNING: method declared to return '%s' returned '%s'\n",
+ declType, objType);
+ LOGW(" failed in %s.%s\n",
+ method->clazz->descriptor, method->name);
+ abortMaybe();
+ return;
+ } else {
+ LOGV("Check %s.%s: %s io %s (SLOW-OK)\n",
+ method->clazz->descriptor, method->name, objType, declType);
+ }
+ }
+}
+
+/*
+ * Check a call into native code.
+ */
+void dvmCheckCallJNIMethod(const u4* args, JValue* pResult,
+ const Method* method, Thread* self)
+{
+ dvmCallJNIMethod(args, pResult, method, self);
+ if (method->shorty[0] == 'L' && !dvmCheckException(self) &&
+ pResult->l != NULL)
+ {
+ checkCallCommon(args, pResult, method, self);
+ }
+}
+
+/*
+ * Check a synchronized call into native code.
+ */
+void dvmCheckCallSynchronizedJNIMethod(const u4* args, JValue* pResult,
+ const Method* method, Thread* self)
+{
+ dvmCallSynchronizedJNIMethod(args, pResult, method, self);
+ if (method->shorty[0] == 'L' && !dvmCheckException(self) &&
+ pResult->l != NULL)
+ {
+ checkCallCommon(args, pResult, method, self);
+ }
+}
+
+
+/*
+ * ===========================================================================
+ * JNI function helpers
+ * ===========================================================================
+ */
+
#define JNI_ENTER() dvmChangeStatus(NULL, THREAD_RUNNING)
#define JNI_EXIT() dvmChangeStatus(NULL, THREAD_NATIVE)
@@ -143,7 +253,7 @@
/*
* Abort if we are configured to bail out on JNI warnings.
*/
-static inline void abortMaybe()
+static void abortMaybe(void)
{
JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
if (vm->warnError) {
@@ -1299,7 +1409,7 @@
return result;
}
-#define GET_STATIC_TYPE_FIELD(_ctype, _jname, _isref) \
+#define GET_STATIC_TYPE_FIELD(_ctype, _jname) \
static _ctype Check_GetStatic##_jname##Field(JNIEnv* env, jclass clazz, \
jfieldID fieldID) \
{ \
@@ -1312,15 +1422,15 @@
CHECK_EXIT(env); \
return result; \
}
-GET_STATIC_TYPE_FIELD(jobject, Object, true);
-GET_STATIC_TYPE_FIELD(jboolean, Boolean, false);
-GET_STATIC_TYPE_FIELD(jbyte, Byte, false);
-GET_STATIC_TYPE_FIELD(jchar, Char, false);
-GET_STATIC_TYPE_FIELD(jshort, Short, false);
-GET_STATIC_TYPE_FIELD(jint, Int, false);
-GET_STATIC_TYPE_FIELD(jlong, Long, false);
-GET_STATIC_TYPE_FIELD(jfloat, Float, false);
-GET_STATIC_TYPE_FIELD(jdouble, Double, false);
+GET_STATIC_TYPE_FIELD(jobject, Object);
+GET_STATIC_TYPE_FIELD(jboolean, Boolean);
+GET_STATIC_TYPE_FIELD(jbyte, Byte);
+GET_STATIC_TYPE_FIELD(jchar, Char);
+GET_STATIC_TYPE_FIELD(jshort, Short);
+GET_STATIC_TYPE_FIELD(jint, Int);
+GET_STATIC_TYPE_FIELD(jlong, Long);
+GET_STATIC_TYPE_FIELD(jfloat, Float);
+GET_STATIC_TYPE_FIELD(jdouble, Double);
#define SET_STATIC_TYPE_FIELD(_ctype, _jname, _ftype) \
static void Check_SetStatic##_jname##Field(JNIEnv* env, jclass clazz, \
@@ -1344,7 +1454,7 @@
SET_STATIC_TYPE_FIELD(jfloat, Float, PRIM_FLOAT);
SET_STATIC_TYPE_FIELD(jdouble, Double, PRIM_DOUBLE);
-#define GET_TYPE_FIELD(_ctype, _jname, _isref) \
+#define GET_TYPE_FIELD(_ctype, _jname) \
static _ctype Check_Get##_jname##Field(JNIEnv* env, jobject obj, \
jfieldID fieldID) \
{ \
@@ -1356,15 +1466,15 @@
CHECK_EXIT(env); \
return result; \
}
-GET_TYPE_FIELD(jobject, Object, true);
-GET_TYPE_FIELD(jboolean, Boolean, false);
-GET_TYPE_FIELD(jbyte, Byte, false);
-GET_TYPE_FIELD(jchar, Char, false);
-GET_TYPE_FIELD(jshort, Short, false);
-GET_TYPE_FIELD(jint, Int, false);
-GET_TYPE_FIELD(jlong, Long, false);
-GET_TYPE_FIELD(jfloat, Float, false);
-GET_TYPE_FIELD(jdouble, Double, false);
+GET_TYPE_FIELD(jobject, Object);
+GET_TYPE_FIELD(jboolean, Boolean);
+GET_TYPE_FIELD(jbyte, Byte);
+GET_TYPE_FIELD(jchar, Char);
+GET_TYPE_FIELD(jshort, Short);
+GET_TYPE_FIELD(jint, Int);
+GET_TYPE_FIELD(jlong, Long);
+GET_TYPE_FIELD(jfloat, Float);
+GET_TYPE_FIELD(jdouble, Double);
#define SET_TYPE_FIELD(_ctype, _jname, _ftype) \
static void Check_Set##_jname##Field(JNIEnv* env, jobject obj, \
@@ -1387,8 +1497,7 @@
SET_TYPE_FIELD(jfloat, Float, PRIM_FLOAT);
SET_TYPE_FIELD(jdouble, Double, PRIM_DOUBLE);
-#define CALL_VIRTUAL(_ctype, _jname, _retfail, _retdecl, _retasgn, _retok, \
- _retsig) \
+#define CALL_VIRTUAL(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
static _ctype Check_Call##_jname##Method(JNIEnv* env, jobject obj, \
jmethodID methodID, ...) \
{ \
@@ -1428,19 +1537,19 @@
CHECK_EXIT(env); \
return _retok; \
}
-CALL_VIRTUAL(jobject, Object, NULL, Object* result, result=, result, 'L');
-CALL_VIRTUAL(jboolean, Boolean, 0, jboolean result, result=, result, 'Z');
-CALL_VIRTUAL(jbyte, Byte, 0, jbyte result, result=, result, 'B');
-CALL_VIRTUAL(jchar, Char, 0, jchar result, result=, result, 'C');
-CALL_VIRTUAL(jshort, Short, 0, jshort result, result=, result, 'S');
-CALL_VIRTUAL(jint, Int, 0, jint result, result=, result, 'I');
-CALL_VIRTUAL(jlong, Long, 0, jlong result, result=, result, 'J');
-CALL_VIRTUAL(jfloat, Float, 0.0f, jfloat result, result=, *(float*)&result, 'F');
-CALL_VIRTUAL(jdouble, Double, 0.0, jdouble result, result=, *(double*)&result, 'D');
-CALL_VIRTUAL(void, Void, , , , , 'V');
+CALL_VIRTUAL(jobject, Object, Object* result, result=, result, 'L');
+CALL_VIRTUAL(jboolean, Boolean, jboolean result, result=, result, 'Z');
+CALL_VIRTUAL(jbyte, Byte, jbyte result, result=, result, 'B');
+CALL_VIRTUAL(jchar, Char, jchar result, result=, result, 'C');
+CALL_VIRTUAL(jshort, Short, jshort result, result=, result, 'S');
+CALL_VIRTUAL(jint, Int, jint result, result=, result, 'I');
+CALL_VIRTUAL(jlong, Long, jlong result, result=, result, 'J');
+CALL_VIRTUAL(jfloat, Float, jfloat result, result=, result, 'F');
+CALL_VIRTUAL(jdouble, Double, jdouble result, result=, result, 'D');
+CALL_VIRTUAL(void, Void, , , , 'V');
-#define CALL_NONVIRTUAL(_ctype, _jname, _retfail, _retdecl, _retasgn, \
- _retok, _retsig) \
+#define CALL_NONVIRTUAL(_ctype, _jname, _retdecl, _retasgn, _retok, \
+ _retsig) \
static _ctype Check_CallNonvirtual##_jname##Method(JNIEnv* env, \
jobject obj, jclass clazz, jmethodID methodID, ...) \
{ \
@@ -1483,20 +1592,19 @@
CHECK_EXIT(env); \
return _retok; \
}
-CALL_NONVIRTUAL(jobject, Object, NULL, Object* result, result=, (Object*)(u4)result, 'L');
-CALL_NONVIRTUAL(jboolean, Boolean, 0, jboolean result, result=, result, 'Z');
-CALL_NONVIRTUAL(jbyte, Byte, 0, jbyte result, result=, result, 'B');
-CALL_NONVIRTUAL(jchar, Char, 0, jchar result, result=, result, 'C');
-CALL_NONVIRTUAL(jshort, Short, 0, jshort result, result=, result, 'S');
-CALL_NONVIRTUAL(jint, Int, 0, jint result, result=, result, 'I');
-CALL_NONVIRTUAL(jlong, Long, 0, jlong result, result=, result, 'J');
-CALL_NONVIRTUAL(jfloat, Float, 0.0f, jfloat result, result=, *(float*)&result, 'F');
-CALL_NONVIRTUAL(jdouble, Double, 0.0, jdouble result, result=, *(double*)&result, 'D');
-CALL_NONVIRTUAL(void, Void, , , , , 'V');
+CALL_NONVIRTUAL(jobject, Object, Object* result, result=, result, 'L');
+CALL_NONVIRTUAL(jboolean, Boolean, jboolean result, result=, result, 'Z');
+CALL_NONVIRTUAL(jbyte, Byte, jbyte result, result=, result, 'B');
+CALL_NONVIRTUAL(jchar, Char, jchar result, result=, result, 'C');
+CALL_NONVIRTUAL(jshort, Short, jshort result, result=, result, 'S');
+CALL_NONVIRTUAL(jint, Int, jint result, result=, result, 'I');
+CALL_NONVIRTUAL(jlong, Long, jlong result, result=, result, 'J');
+CALL_NONVIRTUAL(jfloat, Float, jfloat result, result=, result, 'F');
+CALL_NONVIRTUAL(jdouble, Double, jdouble result, result=, result, 'D');
+CALL_NONVIRTUAL(void, Void, , , , 'V');
-#define CALL_STATIC(_ctype, _jname, _retfail, _retdecl, _retasgn, _retok, \
- _retsig) \
+#define CALL_STATIC(_ctype, _jname, _retdecl, _retasgn, _retok, _retsig) \
static _ctype Check_CallStatic##_jname##Method(JNIEnv* env, \
jclass clazz, jmethodID methodID, ...) \
{ \
@@ -1536,16 +1644,16 @@
CHECK_EXIT(env); \
return _retok; \
}
-CALL_STATIC(jobject, Object, NULL, Object* result, result=, (Object*)(u4)result, 'L');
-CALL_STATIC(jboolean, Boolean, 0, jboolean result, result=, result, 'Z');
-CALL_STATIC(jbyte, Byte, 0, jbyte result, result=, result, 'B');
-CALL_STATIC(jchar, Char, 0, jchar result, result=, result, 'C');
-CALL_STATIC(jshort, Short, 0, jshort result, result=, result, 'S');
-CALL_STATIC(jint, Int, 0, jint result, result=, result, 'I');
-CALL_STATIC(jlong, Long, 0, jlong result, result=, result, 'J');
-CALL_STATIC(jfloat, Float, 0.0f, jfloat result, result=, *(float*)&result, 'F');
-CALL_STATIC(jdouble, Double, 0.0, jdouble result, result=, *(double*)&result, 'D');
-CALL_STATIC(void, Void, , , , , 'V');
+CALL_STATIC(jobject, Object, Object* result, result=, result, 'L');
+CALL_STATIC(jboolean, Boolean, jboolean result, result=, result, 'Z');
+CALL_STATIC(jbyte, Byte, jbyte result, result=, result, 'B');
+CALL_STATIC(jchar, Char, jchar result, result=, result, 'C');
+CALL_STATIC(jshort, Short, jshort result, result=, result, 'S');
+CALL_STATIC(jint, Int, jint result, result=, result, 'I');
+CALL_STATIC(jlong, Long, jlong result, result=, result, 'J');
+CALL_STATIC(jfloat, Float, jfloat result, result=, result, 'F');
+CALL_STATIC(jdouble, Double, jdouble result, result=, result, 'D');
+CALL_STATIC(void, Void, , , , 'V');
static jstring Check_NewString(JNIEnv* env, const jchar* unicodeChars,
jsize len)
diff --git a/vm/Dalvik.h b/vm/Dalvik.h
index 2c7bd7c..618d51a 100644
--- a/vm/Dalvik.h
+++ b/vm/Dalvik.h
@@ -67,11 +67,15 @@
#include "LinearAlloc.h"
#include "analysis/DexVerify.h"
#include "analysis/DexOptimize.h"
+#include "analysis/RegisterMap.h"
#include "Init.h"
#include "libdex/OpCode.h"
#include "libdex/InstrUtils.h"
#include "AllocTracker.h"
#include "PointerSet.h"
+#if defined(WITH_JIT)
+#include "compiler/Compiler.h"
+#endif
#include "Globals.h"
#include "reflect/Reflect.h"
#include "oo/TypeCheck.h"
diff --git a/vm/DalvikVersion.h b/vm/DalvikVersion.h
index 4926fd0..26b52be 100644
--- a/vm/DalvikVersion.h
+++ b/vm/DalvikVersion.h
@@ -24,14 +24,14 @@
* The version we show to tourists.
*/
#define DALVIK_MAJOR_VERSION 1
-#define DALVIK_MINOR_VERSION 0
-#define DALVIK_BUG_VERSION 1
+#define DALVIK_MINOR_VERSION 1
+#define DALVIK_BUG_VERSION 0
/*
* VM build number. This must change whenever something that affects the
* 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 14
+#define DALVIK_VM_BUILD 16
#endif /*_DALVIK_VERSION*/
diff --git a/vm/DvmDex.c b/vm/DvmDex.c
index b5f8d02..6740632 100644
--- a/vm/DvmDex.c
+++ b/vm/DvmDex.c
@@ -171,8 +171,10 @@
int parseFlags = kDexParseDefault;
int result = -1;
+ /* -- file is incomplete, new checksum has not yet been calculated
if (gDvm.verifyDexChecksum)
parseFlags |= kDexParseVerifyChecksum;
+ */
pDexFile = dexFileParse(addr, len, parseFlags);
if (pDexFile == NULL) {
diff --git a/vm/Exception.c b/vm/Exception.c
index 4881640..3a56cc3 100644
--- a/vm/Exception.c
+++ b/vm/Exception.c
@@ -102,6 +102,9 @@
/*
* Cache pointers to some of the exception classes we use locally.
+ *
+ * Note this is NOT called during dexopt optimization. Some of the fields
+ * are initialized by the verifier (dvmVerifyCodeFlow).
*/
bool dvmExceptionStartup(void)
{
@@ -377,6 +380,14 @@
}
}
+ if (cause != NULL) {
+ if (!dvmInstanceof(cause->clazz, gDvm.classJavaLangThrowable)) {
+ LOGE("Tried to init exception with cause '%s'\n",
+ cause->clazz->descriptor);
+ dvmAbort();
+ }
+ }
+
/*
* The Throwable class has four public constructors:
* (1) Throwable()
@@ -625,6 +636,28 @@
}
/*
+ * Get the "cause" field from an exception.
+ *
+ * The Throwable class initializes the "cause" field to "this" to
+ * differentiate between being initialized to null and never being
+ * initialized. We check for that here and convert it to NULL.
+ */
+Object* dvmGetExceptionCause(const Object* exception)
+{
+ if (!dvmInstanceof(exception->clazz, gDvm.classJavaLangThrowable)) {
+ LOGE("Tried to get cause from object of type '%s'\n",
+ exception->clazz->descriptor);
+ dvmAbort();
+ }
+ Object* cause =
+ dvmGetFieldObject(exception, gDvm.offJavaLangThrowable_cause);
+ if (cause == exception)
+ return NULL;
+ else
+ return cause;
+}
+
+/*
* Print the stack trace of the current exception on stderr. This is called
* from the JNI ExceptionDescribe call.
*
@@ -1208,9 +1241,8 @@
for (;;) {
logStackTraceOf(exception);
- cause = (Object*) dvmGetFieldObject(exception,
- gDvm.offJavaLangThrowable_cause);
- if ((cause == NULL) || (cause == exception)) {
+ cause = dvmGetExceptionCause(exception);
+ if (cause == NULL) {
break;
}
LOGI("Caused by:\n");
diff --git a/vm/Exception.h b/vm/Exception.h
index 9887929..4044345 100644
--- a/vm/Exception.h
+++ b/vm/Exception.h
@@ -123,6 +123,13 @@
void dvmWrapException(const char* newExcepStr);
/*
+ * Get the "cause" field from an exception.
+ *
+ * Returns NULL if the field is null or uninitialized.
+ */
+Object* dvmGetExceptionCause(const Object* exception);
+
+/*
* Print the exception stack trace on stderr. Calls the exception's
* print function.
*/
diff --git a/vm/Globals.h b/vm/Globals.h
index 79b9e91..d43a77e 100644
--- a/vm/Globals.h
+++ b/vm/Globals.h
@@ -54,6 +54,9 @@
kExecutionModeUnknown = 0,
kExecutionModeInterpPortable,
kExecutionModeInterpFast,
+#if defined(WITH_JIT)
+ kExecutionModeJit,
+#endif
} ExecutionMode;
/*
@@ -99,6 +102,7 @@
DexOptimizerMode dexOptMode;
DexClassVerifyMode classVerifyMode;
+ bool preciseGc;
bool generateRegisterMaps;
int assertionCtrlCount;
@@ -321,20 +325,19 @@
/*
* The thread code grabs this before suspending all threads. There
- * are four things that can cause a "suspend all":
+ * are a few things that can cause a "suspend all":
* (1) the GC is starting;
* (2) the debugger has sent a "suspend all" request;
* (3) a thread has hit a breakpoint or exception that the debugger
* has marked as a "suspend all" event;
* (4) the SignalCatcher caught a signal that requires suspension.
+ * (5) (if implemented) the JIT needs to perform a heavyweight
+ * rearrangement of the translation cache or JitTable.
*
* Because we use "safe point" self-suspension, it is never safe to
* do a blocking "lock" call on this mutex -- if it has been acquired,
* somebody is probably trying to put you to sleep. The leading '_' is
* intended as a reminder that this lock is special.
- *
- * This lock is also held while attaching an externally-created thread
- * through JNI. That way we can correctly set the initial suspend state.
*/
pthread_mutex_t _threadSuspendLock;
@@ -357,6 +360,12 @@
pthread_cond_t threadSuspendCountCond;
/*
+ * Sum of all threads' suspendCount fields. The JIT needs to know if any
+ * thread is suspended. Guarded by threadSuspendCountLock.
+ */
+ int sumThreadSuspendCount;
+
+ /*
* MUTEX ORDERING: when locking multiple mutexes, always grab them in
* this order to avoid deadlock:
*
@@ -604,8 +613,119 @@
#ifdef COUNT_PRECISE_METHODS
PointerSet* preciseMethods;
#endif
+
+ /* some RegisterMap statistics, useful during development */
+ void* registerMapStats;
};
extern struct DvmGlobals gDvm;
+#if defined(WITH_JIT)
+/*
+ * JIT-specific global state
+ */
+struct DvmJitGlobals {
+ /*
+ * Guards writes to Dalvik PC (dPC), translated code address (codeAddr) and
+ * chain fields within the JIT hash table. Note carefully the access
+ * mechanism.
+ * Only writes are guarded, and the guarded fields must be updated in a
+ * specific order using atomic operations. Further, once a field is
+ * written it cannot be changed without halting all threads.
+ *
+ * The write order is:
+ * 1) codeAddr
+ * 2) dPC
+ * 3) chain [if necessary]
+ *
+ * This mutex also guards both read and write of curJitTableEntries.
+ */
+ pthread_mutex_t tableLock;
+
+ /* The JIT hash table. Note that for access speed, copies of this pointer
+ * are stored in each thread. */
+ struct JitEntry *pJitEntryTable;
+
+ /* Array of profile threshold counters */
+ unsigned char *pProfTable;
+ unsigned char *pProfTableCopy;
+
+ /* Size of JIT hash table in entries. Must be a power of 2 */
+ unsigned int jitTableSize;
+
+ /* Mask used in hash function for JitTable. Should be jitTableSize-1 */
+ unsigned int jitTableMask;
+
+ /* How many entries in the JitEntryTable are in use */
+ unsigned int jitTableEntriesUsed;
+
+ /* Trigger for trace selection */
+ unsigned short threshold;
+
+ /* JIT Compiler Control */
+ bool haltCompilerThread;
+ bool blockingMode;
+ pthread_t compilerHandle;
+ pthread_mutex_t compilerLock;
+ pthread_cond_t compilerQueueActivity;
+ pthread_cond_t compilerQueueEmpty;
+ int compilerQueueLength;
+ int compilerHighWater;
+ int compilerWorkEnqueueIndex;
+ int compilerWorkDequeueIndex;
+ CompilerWorkOrder compilerWorkQueue[COMPILER_WORK_QUEUE_SIZE];
+
+ /* JIT internal stats */
+ int compilerMaxQueued;
+ int addrLookupsFound;
+ int addrLookupsNotFound;
+ int noChainExit;
+ int normalExit;
+ int puntExit;
+ int translationChains;
+ int invokeNoOpt;
+ int InvokeChain;
+ int returnOp;
+
+ /* Compiled code cache */
+ void* codeCache;
+
+ /* Bytes used by the code templates */
+ unsigned int templateSize;
+
+ /* Bytes already used in the code cache */
+ unsigned int codeCacheByteUsed;
+
+ /* Number of installed compilations in the cache */
+ unsigned int numCompilations;
+
+ /* Flag to indicate that the code cache is full */
+ bool codeCacheFull;
+
+ /* true/false: compile/reject opcodes specified in the -Xjitop list */
+ bool includeSelectedOp;
+
+ /* true/false: compile/reject methods specified in the -Xjitmethod list */
+ bool includeSelectedMethod;
+
+ /* Disable JIT for selected opcodes - one bit for each opcode */
+ char opList[32];
+
+ /* Disable JIT for selected methods */
+ HashTable *methodTable;
+
+ /* Flag to dump all compiled code */
+ bool printMe;
+
+ /* Flag to count trace execution */
+ bool profile;
+
+ /* Table to track the overall and trace statistics of hot methods */
+ HashTable* methodStatsTable;
+};
+
+extern struct DvmJitGlobals gDvmJit;
+
+#endif
+
#endif /*_DALVIK_GLOBALS*/
diff --git a/vm/Init.c b/vm/Init.c
index 176910c..3663745 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -20,6 +20,7 @@
#include "Dalvik.h"
#include "test/Test.h"
#include "mterp/Mterp.h"
+#include "Hash.h"
#include <stdlib.h>
#include <stdio.h>
@@ -49,6 +50,11 @@
/* global state */
struct DvmGlobals gDvm;
+/* JIT-specific global state */
+#if defined(WITH_JIT)
+struct DvmJitGlobals gDvmJit;
+#endif
+
/*
* Show usage.
*
@@ -83,8 +89,13 @@
kMinStackSize / 1024, kMaxStackSize / 1024);
dvmFprintf(stderr, " -Xverify:{none,remote,all}\n");
dvmFprintf(stderr, " -Xrs\n");
+#if defined(WITH_JIT)
+ dvmFprintf(stderr,
+ " -Xint (extended to accept ':portable', ':fast' and ':jit')\n");
+#else
dvmFprintf(stderr,
" -Xint (extended to accept ':portable' and ':fast')\n");
+#endif
dvmFprintf(stderr, "\n");
dvmFprintf(stderr, "These are unique to Dalvik:\n");
dvmFprintf(stderr, " -Xzygote\n");
@@ -95,8 +106,21 @@
dvmFprintf(stderr, " -Xjniopts:{warnonly,forcecopy}\n");
dvmFprintf(stderr, " -Xdeadlockpredict:{off,warn,err,abort}\n");
dvmFprintf(stderr, " -Xstacktracefile:<filename>\n");
+ dvmFprintf(stderr, " -Xgc:[no]precise\n");
dvmFprintf(stderr, " -Xgenregmap\n");
dvmFprintf(stderr, " -Xcheckdexsum\n");
+#if defined(WITH_JIT)
+ dvmFprintf(stderr, " -Xincludeselectedop\n");
+ dvmFprintf(stderr, " -Xjitop:hexopvalue[-endvalue]"
+ "[,hexopvalue[-endvalue]]*\n");
+ dvmFprintf(stderr, " -Xincludeselectedmethod\n");
+ dvmFprintf(stderr, " -Xthreshold:decimalvalue\n");
+ dvmFprintf(stderr, " -Xblocking\n");
+ dvmFprintf(stderr, " -Xjitmethod:signture[,signature]* "
+ "(eg Ljava/lang/String\\;replace)\n");
+ dvmFprintf(stderr, " -Xjitverbose\n");
+ dvmFprintf(stderr, " -Xjitprofile\n");
+#endif
dvmFprintf(stderr, "\n");
dvmFprintf(stderr, "Configured with:"
#ifdef WITH_DEBUGGER
@@ -132,6 +156,9 @@
#ifdef WITH_EXTRA_OBJECT_VALIDATION
" extra_object_validation"
#endif
+#ifdef WITH_EXTRA_GC_CHECKS
+ " extra_gc_checks"
+#endif
#ifdef WITH_DALVIK_ASSERT
" dalvik_assert"
#endif
@@ -157,6 +184,9 @@
#elif DVM_RESOLVER_CACHE == DVM_RC_NO_CACHE
" resolver_cache_disabled"
#endif
+#if defined(WITH_JIT)
+ " with_jit"
+#endif
);
#ifdef DVM_SHOW_EXCEPTION
dvmFprintf(stderr, " show_exception=%d", DVM_SHOW_EXCEPTION);
@@ -527,6 +557,97 @@
free(gDvm.assertionCtrl);
}
+#if defined(WITH_JIT)
+/* Parse -Xjitop to selectively turn on/off certain opcodes for JIT */
+static void processXjitop(const char *opt)
+{
+ if (opt[7] == ':') {
+ const char *startPtr = &opt[8];
+ char *endPtr = NULL;
+
+ do {
+ long startValue, endValue;
+
+ startValue = strtol(startPtr, &endPtr, 16);
+ if (startPtr != endPtr) {
+ /* Just in case value is out of range */
+ startValue &= 0xff;
+
+ if (*endPtr == '-') {
+ endValue = strtol(endPtr+1, &endPtr, 16);
+ endValue &= 0xff;
+ } else {
+ endValue = startValue;
+ }
+
+ for (; startValue <= endValue; startValue++) {
+ LOGW("Dalvik opcode %x is selected for debugging",
+ (unsigned int) startValue);
+ /* Mark the corresponding bit to 1 */
+ gDvmJit.opList[startValue >> 3] |=
+ 1 << (startValue & 0x7);
+ }
+
+ if (*endPtr == 0) {
+ break;
+ }
+
+ startPtr = endPtr + 1;
+
+ continue;
+ } else {
+ if (*endPtr != 0) {
+ dvmFprintf(stderr,
+ "Warning: Unrecognized opcode value substring "
+ "%s\n", endPtr);
+ }
+ break;
+ }
+ } while (1);
+ } else {
+ int i;
+ for (i = 0; i < 32; i++) {
+ gDvmJit.opList[i] = 0xff;
+ }
+ dvmFprintf(stderr, "Warning: select all opcodes\n");
+ }
+}
+
+/* Parse -Xjitmethod to selectively turn on/off certain methods for JIT */
+static void processXjitmethod(const char *opt)
+{
+ char *buf = strdup(&opt[12]);
+ char *start, *end;
+
+ gDvmJit.methodTable = dvmHashTableCreate(8, NULL);
+
+ start = buf;
+ /*
+ * Break comma-separated method signatures and enter them into the hash
+ * table individually.
+ */
+ do {
+ int hashValue;
+
+ end = strchr(start, ',');
+ if (end) {
+ *end = 0;
+ }
+
+ hashValue = dvmComputeUtf8Hash(start);
+
+ dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+ strdup(start),
+ (HashCompareFunc) strcmp, true);
+ if (end) {
+ start = end + 1;
+ } else {
+ break;
+ }
+ } while (1);
+ free(buf);
+}
+#endif
/*
* Process an argument vector full of options. Unlike standard C programs,
@@ -756,6 +877,10 @@
gDvm.executionMode = kExecutionModeInterpPortable;
else if (strcmp(argv[i] + 6, "fast") == 0)
gDvm.executionMode = kExecutionModeInterpFast;
+#ifdef WITH_JIT
+ else if (strcmp(argv[i] + 6, "jit") == 0)
+ gDvm.executionMode = kExecutionModeJit;
+#endif
else {
dvmFprintf(stderr,
"Warning: Unrecognized interpreter mode %s\n",argv[i]);
@@ -765,6 +890,25 @@
/* disable JIT -- nothing to do here for now */
}
+#ifdef WITH_JIT
+ } else if (strncmp(argv[i], "-Xjitop", 7) == 0) {
+ processXjitop(argv[i]);
+ } else if (strncmp(argv[i], "-Xjitmethod", 11) == 0) {
+ processXjitmethod(argv[i]);
+ } else if (strncmp(argv[i], "-Xblocking", 10) == 0) {
+ gDvmJit.blockingMode = true;
+ } else if (strncmp(argv[i], "-Xthreshold:", 12) == 0) {
+ gDvmJit.threshold = atoi(argv[i] + 12);
+ } else if (strncmp(argv[i], "-Xincludeselectedop", 19) == 0) {
+ gDvmJit.includeSelectedOp = true;
+ } else if (strncmp(argv[i], "-Xincludeselectedmethod", 23) == 0) {
+ gDvmJit.includeSelectedMethod = true;
+ } else if (strncmp(argv[i], "-Xjitverbose", 12) == 0) {
+ gDvmJit.printMe = true;
+ } else if (strncmp(argv[i], "-Xjitprofile", 12) == 0) {
+ gDvmJit.profile = true;
+#endif
+
} else if (strncmp(argv[i], "-Xdeadlockpredict:", 18) == 0) {
#ifdef WITH_DEADLOCK_PREDICTION
if (strcmp(argv[i] + 18, "off") == 0)
@@ -788,6 +932,18 @@
} else if (strcmp(argv[i], "-Xgenregmap") == 0) {
gDvm.generateRegisterMaps = true;
+ LOGD("Register maps will be generated during verification\n");
+
+ } else if (strncmp(argv[i], "-Xgc:", 5) == 0) {
+ if (strcmp(argv[i] + 5, "precise") == 0)
+ gDvm.preciseGc = true;
+ else if (strcmp(argv[i] + 5, "noprecise") == 0)
+ gDvm.preciseGc = false;
+ else {
+ dvmFprintf(stderr, "Bad value for -Xgc");
+ return -1;
+ }
+ LOGD("Precise GC configured %s\n", gDvm.preciseGc ? "ON" : "OFF");
} else if (strcmp(argv[i], "-Xcheckdexsum") == 0) {
gDvm.verifyDexChecksum = true;
@@ -810,6 +966,8 @@
/*
* Set defaults for fields altered or modified by arguments.
+ *
+ * Globals are initialized to 0 (a/k/a NULL or false).
*/
static void setCommandLineDefaults()
{
@@ -849,7 +1007,19 @@
* we know we're using the "desktop" build we should probably be
* using "portable" rather than "fast".
*/
+#if defined(WITH_JIT)
+ gDvm.executionMode = kExecutionModeJit;
+ /*
+ * TODO - check system property and insert command-line options in
+ * frameworks/base/core/jni/AndroidRuntime.cpp
+ */
+ gDvmJit.blockingMode = false;
+ gDvmJit.jitTableSize = 512;
+ gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+ gDvmJit.threshold = 200;
+#else
gDvm.executionMode = kExecutionModeInterpFast;
+#endif
}
@@ -886,6 +1056,9 @@
sigemptyset(&mask);
sigaddset(&mask, SIGQUIT);
sigaddset(&mask, SIGUSR1); // used to initiate heap dump
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+ sigaddset(&mask, SIGUSR2); // used to investigate JIT internals
+#endif
//sigaddset(&mask, SIGPIPE);
cc = sigprocmask(SIG_BLOCK, &mask, NULL);
assert(cc == 0);
@@ -936,6 +1109,14 @@
goto fail;
}
+#if WITH_EXTRA_GC_CHECKS > 1
+ /* only "portable" interp has the extra goodies */
+ if (gDvm.executionMode != kExecutionModeInterpPortable) {
+ LOGI("Switching to 'portable' interpreter for GC checks\n");
+ gDvm.executionMode = kExecutionModeInterpPortable;
+ }
+#endif
+
/* configure signal handling */
if (!gDvm.reduceSignals)
blockSignals();
@@ -957,6 +1138,8 @@
goto fail;
if (!dvmVerificationStartup())
goto fail;
+ if (!dvmRegisterMapStartup())
+ goto fail;
if (!dvmInstanceofStartup())
goto fail;
if (!dvmClassStartup())
@@ -1167,6 +1350,11 @@
(int)(endHeap-startHeap), (int)(endQuit-startQuit),
(int)(endJdwp-startJdwp), (int)(endJdwp-startHeap));
+#ifdef WITH_JIT
+ if (!dvmJitStartup())
+ return false;
+#endif
+
return true;
}
@@ -1290,6 +1478,8 @@
goto fail;
if (!dvmVerificationStartup())
goto fail;
+ if (!dvmRegisterMapStartup())
+ goto fail;
if (!dvmInstanceofStartup())
goto fail;
if (!dvmClassStartup())
@@ -1350,6 +1540,11 @@
/* shut down stdout/stderr conversion */
dvmStdioConverterShutdown();
+#ifdef WITH_JIT
+ /* tell the compiler to shut down if it was started */
+ dvmJitShutdown();
+#endif
+
/*
* Kill any daemon threads that still exist. Actively-running threads
* are likely to crash the process if they continue to execute while
@@ -1370,6 +1565,7 @@
dvmThreadShutdown();
dvmClassShutdown();
dvmVerificationShutdown();
+ dvmRegisterMapShutdown();
dvmInstanceofShutdown();
dvmInlineNativeShutdown();
dvmGcShutdown();
diff --git a/vm/Init.h b/vm/Init.h
index 8549338..63051a2 100644
--- a/vm/Init.h
+++ b/vm/Init.h
@@ -41,9 +41,14 @@
DexClassVerifyMode verifyMode, int dexoptFlags);
/*
- * Unconditionally abort the entire VM. Try not to use this.
+ * Replacement for fprintf() when we want to send a message to the console.
+ * This defaults to fprintf(), but will use the JNI fprintf callback if
+ * one was provided.
*/
-int dvmFprintf(FILE* fp, const char* format, ...);
-void dvmAbort(void);
+int dvmFprintf(FILE* fp, const char* format, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 2, 3)))
+#endif
+ ;
#endif /*_DALVIK_INIT*/
diff --git a/vm/InlineNative.c b/vm/InlineNative.c
index 49025a6..6364e94 100644
--- a/vm/InlineNative.c
+++ b/vm/InlineNative.c
@@ -20,6 +20,8 @@
*/
#include "Dalvik.h"
+#include <math.h>
+
#ifdef HAVE__MEMCMP16
/* hand-coded assembly implementation, available on some platforms */
//#warning "trying memcmp16"
@@ -388,6 +390,154 @@
/*
* ===========================================================================
+ * java.lang.Math
+ * ===========================================================================
+ */
+
+/*
+ * public static int abs(int)
+ */
+static bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ s4 val = (s4) arg0;
+ pResult->i = (val >= 0) ? val : -val;
+ return true;
+}
+
+/*
+ * public static long abs(long)
+ */
+static bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ union {
+ u4 arg[2];
+ s8 ll;
+ } convert;
+
+ convert.arg[0] = arg0;
+ convert.arg[1] = arg1;
+ s8 val = convert.ll;
+ pResult->j = (val >= 0) ? val : -val;
+ return true;
+}
+
+/*
+ * public static float abs(float)
+ */
+static bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ union {
+ u4 arg;
+ float ff;
+ } convert;
+
+ /* clear the sign bit; assumes a fairly common fp representation */
+ convert.arg = arg0 & 0x7fffffff;
+ pResult->f = convert.ff;
+ return true;
+}
+
+/*
+ * public static float abs(float)
+ */
+static bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ union {
+ u4 arg[2];
+ s8 ll;
+ double dd;
+ } convert;
+
+ /* clear the sign bit in the (endian-dependent) high word */
+ convert.arg[0] = arg0;
+ convert.arg[1] = arg1;
+ convert.ll &= 0x7fffffffffffffffULL;
+ pResult->d = convert.dd;
+ return true;
+}
+
+/*
+ * public static int min(int)
+ */
+static bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ pResult->i = ((s4) arg0 < (s4) arg1) ? arg0 : arg1;
+ return true;
+}
+
+/*
+ * public static int max(int)
+ */
+static bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ pResult->i = ((s4) arg0 > (s4) arg1) ? arg0 : arg1;
+ return true;
+}
+
+/*
+ * public static double sqrt(double)
+ *
+ * With ARM VFP enabled, gcc turns this into an fsqrtd instruction, followed
+ * by an fcmpd of the result against itself. If it doesn't match (i.e.
+ * it's NaN), the libm sqrt() is invoked.
+ */
+static bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ union {
+ u4 arg[2];
+ double dd;
+ } convert;
+
+ convert.arg[0] = arg0;
+ convert.arg[1] = arg1;
+ pResult->d = sqrt(convert.dd);
+ return true;
+}
+
+/*
+ * public static double cos(double)
+ */
+static bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ union {
+ u4 arg[2];
+ double dd;
+ } convert;
+
+ convert.arg[0] = arg0;
+ convert.arg[1] = arg1;
+ pResult->d = cos(convert.dd);
+ return true;
+}
+
+/*
+ * public static double sin(double)
+ */
+static bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
+ JValue* pResult)
+{
+ union {
+ u4 arg[2];
+ double dd;
+ } convert;
+
+ convert.arg[0] = arg0;
+ convert.arg[1] = arg1;
+ pResult->d = sin(convert.dd);
+ return true;
+}
+
+
+/*
+ * ===========================================================================
* Infrastructure
* ===========================================================================
*/
@@ -406,6 +556,7 @@
{ org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
"Lorg/apache/harmony/dalvik/NativeTestTarget;",
"emptyInlineMethod", "()V" },
+
{ javaLangString_charAt,
"Ljava/lang/String;", "charAt", "(I)C" },
{ javaLangString_compareTo,
@@ -414,6 +565,25 @@
"Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
{ javaLangString_length,
"Ljava/lang/String;", "length", "()I" },
+
+ { javaLangMath_abs_int,
+ "Ljava/lang/Math;", "abs", "(I)I" },
+ { javaLangMath_abs_long,
+ "Ljava/lang/Math;", "abs", "(J)J" },
+ { javaLangMath_abs_float,
+ "Ljava/lang/Math;", "abs", "(F)F" },
+ { javaLangMath_abs_double,
+ "Ljava/lang/Math;", "abs", "(D)D" },
+ { javaLangMath_min_int,
+ "Ljava/lang/Math;", "min", "(II)I" },
+ { javaLangMath_max_int,
+ "Ljava/lang/Math;", "max", "(II)I" },
+ { javaLangMath_sqrt,
+ "Ljava/lang/Math;", "sqrt", "(D)D" },
+ { javaLangMath_cos,
+ "Ljava/lang/Math;", "cos", "(D)D" },
+ { javaLangMath_sin,
+ "Ljava/lang/Math;", "sin", "(D)D" },
};
diff --git a/vm/Inlines.c b/vm/Inlines.c
index 57405e3..e314448 100644
--- a/vm/Inlines.c
+++ b/vm/Inlines.c
@@ -21,6 +21,7 @@
#define _DALVIK_GEN_INLINES
#include "Dalvik.h"
#include "analysis/CodeVerify.h"
+#include "analysis/RegisterMap.h"
#include "mterp/c/header.c"
#undef LOG_TAG
diff --git a/vm/Jni.c b/vm/Jni.c
index e56e68d..831a349 100644
--- a/vm/Jni.c
+++ b/vm/Jni.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Dalvik implementation of JNI interfaces.
*/
@@ -859,14 +860,7 @@
/* keep going, I guess */
}
- /*
- * Point "nativeFunc" at the JNI bridge, and overload "insns" to
- * point at the actual function.
- */
- if (dvmIsSynchronizedMethod(method))
- dvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, fnPtr);
- else
- dvmSetNativeFunc(method, dvmCallJNIMethod, fnPtr);
+ dvmUseJNIBridge(method, fnPtr);
LOGV("JNI-registered %s.%s %s\n", clazz->descriptor, methodName,
signature);
@@ -877,6 +871,34 @@
}
/*
+ * Returns "true" if CheckJNI is enabled in the VM.
+ */
+static bool dvmIsCheckJNIEnabled(void)
+{
+ JavaVMExt* vm = (JavaVMExt*) gDvm.vmList;
+ return vm->useChecked;
+}
+
+/*
+ * Point "method->nativeFunc" at the JNI bridge, and overload "method->insns"
+ * to point at the actual function.
+ */
+void dvmUseJNIBridge(Method* method, void* func)
+{
+ if (dvmIsCheckJNIEnabled()) {
+ if (dvmIsSynchronizedMethod(method))
+ dvmSetNativeFunc(method, dvmCheckCallSynchronizedJNIMethod, func);
+ else
+ dvmSetNativeFunc(method, dvmCheckCallJNIMethod, func);
+ } else {
+ if (dvmIsSynchronizedMethod(method))
+ dvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, func);
+ else
+ dvmSetNativeFunc(method, dvmCallJNIMethod, func);
+ }
+}
+
+/*
* Get the method currently being executed by examining the interp stack.
*/
const Method* dvmGetCurrentJNIMethod(void)
@@ -2653,7 +2675,7 @@
{
JNI_ENTER();
jobjectRefType type;
-
+
if (obj == NULL)
type = JNIInvalidRefType;
else
@@ -3393,6 +3415,10 @@
/*
* Enable "checked JNI" after the VM has partially started. This must
* only be called in "zygote" mode, when we have one thread running.
+ *
+ * This doesn't attempt to rewrite the JNI call bridge associated with
+ * native methods, so we won't get those checks for any methods that have
+ * already been resolved.
*/
void dvmLateEnableCheckedJni(void)
{
diff --git a/vm/JniInternal.h b/vm/JniInternal.h
index a890934..e60b088 100644
--- a/vm/JniInternal.h
+++ b/vm/JniInternal.h
@@ -113,11 +113,23 @@
/*
* JNI call bridges. Not usually called directly.
+ *
+ * The "Check" versions are used when CheckJNI is enabled.
*/
void dvmCallJNIMethod(const u4* args, JValue* pResult, const Method* method,
Thread* self);
void dvmCallSynchronizedJNIMethod(const u4* args, JValue* pResult,
const Method* method, Thread* self);
+void dvmCheckCallJNIMethod(const u4* args, JValue* pResult,
+ const Method* method, Thread* self);
+void dvmCheckCallSynchronizedJNIMethod(const u4* args, JValue* pResult,
+ const Method* method, Thread* self);
+
+/*
+ * Configure "method" to use the JNI bridge to call "func".
+ */
+void dvmUseJNIBridge(Method* method, void* func);
+
/*
* Enable the "checked" versions.
diff --git a/vm/LinearAlloc.c b/vm/LinearAlloc.c
index 77802ee..84bb103 100644
--- a/vm/LinearAlloc.c
+++ b/vm/LinearAlloc.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Linear memory allocation, tied to class loaders.
*/
@@ -68,7 +69,7 @@
#define BLOCK_ALIGN 8
/* default length of memory segment (worst case is probably "dexopt") */
-#define DEFAULT_MAX_LENGTH (4*1024*1024)
+#define DEFAULT_MAX_LENGTH (5*1024*1024)
/* leave enough space for a length word */
#define HEADER_EXTRA 4
@@ -148,7 +149,7 @@
LOGE("LinearAlloc mmap(%d) failed: %s\n", pHdr->mapLength,
strerror(errno));
free(pHdr);
- close(fd);
+ close(fd);
return NULL;
}
@@ -313,7 +314,8 @@
* works if the users of these functions actually free everything
* they allocate.
*/
- LOGE("LinearAlloc exceeded capacity, last=%d\n", (int) size);
+ LOGE("LinearAlloc exceeded capacity (%d), last=%d\n",
+ pHdr->mapLength, (int) size);
dvmAbort();
}
diff --git a/vm/Misc.c b/vm/Misc.c
index ef9c4af..6b1372c 100644
--- a/vm/Misc.c
+++ b/vm/Misc.c
@@ -297,6 +297,15 @@
}
/*
+ * Mark all bits bit as "clear".
+ */
+void dvmClearAllBits(BitVector* pBits)
+{
+ int count = pBits->storageSize;
+ memset(pBits->storage, 0, count * sizeof(u4));
+}
+
+/*
* Determine whether or not the specified bit is set.
*/
bool dvmIsBitSet(const BitVector* pBits, int num)
@@ -334,7 +343,6 @@
return count;
}
-
/*
* Return a newly-allocated string in which all occurrences of '.' have
* been changed to '/'. If we find a '/' in the original string, NULL
diff --git a/vm/Misc.h b/vm/Misc.h
index 5f3af7b..1566161 100644
--- a/vm/Misc.h
+++ b/vm/Misc.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Miscellaneous utility functions.
*/
@@ -51,28 +52,6 @@
conv.in = val;
return conv.out;
}
-#if 0
-INLINE float dvmU8ToFloat(u8 val) {
- union { u8 in; float out; } conv;
- conv.in = val;
- return conv.out;
-}
-INLINE u8 dvmFloatToU8(float val) {
- union { float in; u8 out; } conv;
- conv.in = val;
- return conv.out;
-}
-INLINE double dvmU8ToDouble(u8 val) {
- union { u8 in; double out; } conv;
- conv.in = val;
- return conv.out;
-}
-INLINE u8 dvmDoubleToU8(double val) {
- union { double in; u8 out; } conv;
- conv.in = val;
- return conv.out;
-}
-#endif
/*
* Print a hex dump to the log file.
@@ -143,7 +122,11 @@
* Print a debug message.
*/
void dvmPrintDebugMessage(const DebugOutputTarget* target, const char* format,
- ...);
+ ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 2, 3)))
+#endif
+ ;
/*
@@ -175,6 +158,7 @@
int dvmAllocBit(BitVector* pBits);
bool dvmSetBit(BitVector* pBits, int num);
void dvmClearBit(BitVector* pBits, int num);
+void dvmClearAllBits(BitVector* pBits);
bool dvmIsBitSet(const BitVector* pBits, int num);
/* count the number of bits that have been set */
@@ -277,6 +261,15 @@
*/
bool dvmSetCloseOnExec(int fd);
+/*
+ * Unconditionally abort the entire VM. Try not to use this.
+ */
+void dvmAbort(void)
+#if defined(__GNUC__)
+ __attribute__ ((noreturn))
+#endif
+ ;
+
#if (!HAVE_STRLCPY)
/* Implementation of strlcpy() for platforms that don't already have it. */
size_t strlcpy(char *dst, const char *src, size_t size);
diff --git a/vm/Native.c b/vm/Native.c
index 7a153d6..dcfb469 100644
--- a/vm/Native.c
+++ b/vm/Native.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Native method resolution.
*
@@ -61,6 +62,10 @@
* Initializes method's class if necessary.
*
* An exception is thrown on resolution failure.
+ *
+ * (This should not be taking "const Method*", because it modifies the
+ * structure, but the declaration needs to match the DalvikBridgeFunc
+ * type definition.)
*/
void dvmResolveNativeMethod(const u4* args, JValue* pResult,
const Method* method, Thread* self)
@@ -107,10 +112,8 @@
/* now scan any DLLs we have loaded for JNI signatures */
func = lookupSharedLibMethod(method);
if (func != NULL) {
- if (dvmIsSynchronizedMethod(method))
- dvmSetNativeFunc(method, dvmCallSynchronizedJNIMethod, func);
- else
- dvmSetNativeFunc(method, dvmCallJNIMethod, func);
+ /* found it, point it at the JNI bridge and then call it */
+ dvmUseJNIBridge((Method*) method, func);
dvmCallJNIMethod(args, pResult, method, self);
return;
}
@@ -411,21 +414,35 @@
* doesn't have to search through LD_LIBRARY_PATH. (It may do so to
* resolve this library's dependencies though.)
*
- * Failures here are expected when java.library.path has several entries.
+ * Failures here are expected when java.library.path has several entries
+ * and we have to hunt for the lib.
*
* The current android-arm dynamic linker implementation tends to
* return "Cannot find library" from dlerror() regardless of the actual
- * problem. A more useful diagnostic may be sent to stdout/stderr,
- * but often that's not visible. Some things to try:
+ * problem. A more useful diagnostic may be sent to stdout/stderr if
+ * linker diagnostics are enabled, but that's not usually visible in
+ * Android apps. Some things to try:
* - make sure the library exists on the device
* - verify that the right path is being opened (the debug log message
* above can help with that)
- * - check to see if the library is valid
+ * - check to see if the library is valid (e.g. not zero bytes long)
* - check config/prelink-linux-arm.map to ensure that the library
* is listed and is not being overrun by the previous entry (if
- * loading suddenly stops working, this is a good one to check)
+ * loading suddenly stops working on a prelinked library, this is
+ * a good one to check)
+ * - write a trivial app that calls sleep() then dlopen(), attach
+ * to it with "strace -p <pid>" while it sleeps, and watch for
+ * attempts to open nonexistent dependent shared libs
+ *
+ * This can execute slowly for a large library on a busy system, so we
+ * want to switch from RUNNING to VMWAIT while it executes. This allows
+ * the GC to ignore us.
*/
+ Thread* self = dvmThreadSelf();
+ int oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
handle = dlopen(pathName, RTLD_LAZY);
+ dvmChangeStatus(self, oldStatus);
+
if (handle == NULL) {
LOGI("Unable to dlopen(%s): %s\n", pathName, dlerror());
return false;
@@ -461,9 +478,9 @@
Object* prevOverride = self->classLoaderOverride;
self->classLoaderOverride = classLoader;
- dvmChangeStatus(NULL, THREAD_NATIVE);
+ oldStatus = dvmChangeStatus(self, THREAD_NATIVE);
version = (*func)(gDvm.vmList, NULL);
- dvmChangeStatus(NULL, THREAD_RUNNING);
+ dvmChangeStatus(self, oldStatus);
self->classLoaderOverride = prevOverride;
if (version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 &&
diff --git a/vm/Profile.c b/vm/Profile.c
index 8e19b34..7f39f1a 100644
--- a/vm/Profile.c
+++ b/vm/Profile.c
@@ -64,6 +64,8 @@
#define TRACE_MAGIC 0x574f4c53
#define TRACE_HEADER_LEN 32
+#define FILL_PATTERN 0xeeeeeeee
+
/*
* Get the wall-clock date/time, in usec.
@@ -364,7 +366,7 @@
dvmThrowException("Ljava/lang/RuntimeException;", "file open failed");
goto fail;
}
- memset(state->buf, 0xee, bufferSize);
+ memset(state->buf, (char)FILL_PATTERN, bufferSize);
state->bufferSize = bufferSize;
state->overflow = false;
@@ -418,10 +420,10 @@
* Run through the data buffer and pull out the methods that were visited.
* Set a mark so that we know which ones to output.
*/
-static void markTouchedMethods(void)
+static void markTouchedMethods(int endOffset)
{
u1* ptr = gDvm.methodTrace.buf + TRACE_HEADER_LEN;
- u1* end = gDvm.methodTrace.buf + gDvm.methodTrace.curOffset;
+ u1* end = gDvm.methodTrace.buf + endOffset;
unsigned int methodVal;
Method* method;
@@ -508,13 +510,56 @@
state->traceEnabled = false;
MEM_BARRIER();
sched_yield();
+ usleep(250 * 1000);
if ((state->flags & TRACE_ALLOC_COUNTS) != 0)
dvmStopAllocCounting();
+ /*
+ * It's possible under some circumstances for a thread to have advanced
+ * the data pointer but not written the method value. It's possible
+ * (though less likely) for the data pointer to be advanced, or partial
+ * data written, while we're doing work here.
+ *
+ * To avoid seeing partially-written data, we grab state->curOffset here,
+ * and use our local copy from here on. We then scan through what's
+ * already written. If we see the fill pattern in what should be the
+ * method pointer, we cut things off early. (If we don't, we'll fail
+ * when we dereference the pointer.)
+ *
+ * There's a theoretical possibility of interrupting another thread
+ * after it has partially written the method pointer, in which case
+ * we'll likely crash when we dereference it. The possibility of
+ * this actually happening should be at or near zero. Fixing it
+ * completely could be done by writing the thread number last and
+ * using a sentinel value to indicate a partially-written record,
+ * but that requires memory barriers.
+ */
+ int finalCurOffset = state->curOffset;
+
+ if (finalCurOffset > TRACE_HEADER_LEN) {
+ u4 fillVal = METHOD_ID(FILL_PATTERN);
+ u1* scanPtr = state->buf + TRACE_HEADER_LEN;
+
+ while (scanPtr < state->buf + finalCurOffset) {
+ u4 methodVal = scanPtr[1] | (scanPtr[2] << 8) | (scanPtr[3] << 16)
+ | (scanPtr[4] << 24);
+ if (METHOD_ID(methodVal) == fillVal) {
+ u1* scanBase = state->buf + TRACE_HEADER_LEN;
+ LOGW("Found unfilled record at %d (of %d)\n",
+ (scanPtr - scanBase) / TRACE_REC_SIZE,
+ (finalCurOffset - TRACE_HEADER_LEN) / TRACE_REC_SIZE);
+ finalCurOffset = scanPtr - state->buf;
+ break;
+ }
+
+ scanPtr += TRACE_REC_SIZE;
+ }
+ }
+
LOGI("TRACE STOPPED%s: writing %d records\n",
state->overflow ? " (NOTE: overflowed buffer)" : "",
- (state->curOffset - TRACE_HEADER_LEN) / TRACE_REC_SIZE);
+ (finalCurOffset - TRACE_HEADER_LEN) / TRACE_REC_SIZE);
if (gDvm.debuggerActive) {
LOGW("WARNING: a debugger is active; method-tracing results "
"will be skewed\n");
@@ -525,7 +570,7 @@
*/
u4 clockNsec = getClockOverhead();
- markTouchedMethods();
+ markTouchedMethods(finalCurOffset);
fprintf(state->traceFile, "%cversion\n", TOKEN_CHAR);
fprintf(state->traceFile, "%d\n", TRACE_VERSION);
@@ -538,7 +583,7 @@
#endif
fprintf(state->traceFile, "elapsed-time-usec=%llu\n", elapsed);
fprintf(state->traceFile, "num-method-calls=%d\n",
- (state->curOffset - TRACE_HEADER_LEN) / TRACE_REC_SIZE);
+ (finalCurOffset - TRACE_HEADER_LEN) / TRACE_REC_SIZE);
fprintf(state->traceFile, "clock-call-overhead-nsec=%d\n", clockNsec);
fprintf(state->traceFile, "vm=dalvik\n");
if ((state->flags & TRACE_ALLOC_COUNTS) != 0) {
@@ -555,8 +600,8 @@
dumpMethodList(state->traceFile);
fprintf(state->traceFile, "%cend\n", TOKEN_CHAR);
- if (fwrite(state->buf, state->curOffset, 1, state->traceFile) != 1) {
- LOGE("trace fwrite(%d) failed, errno=%d\n", state->curOffset, errno);
+ if (fwrite(state->buf, finalCurOffset, 1, state->traceFile) != 1) {
+ LOGE("trace fwrite(%d) failed, errno=%d\n", finalCurOffset, errno);
dvmThrowException("Ljava/lang/RuntimeException;", "data write failed");
goto bail;
}
@@ -674,7 +719,7 @@
* Fortunately, the trace tools can get by without the address, but
* it would be nice to fix this.
*/
- addr = method->nativeFunc;
+ addr = (u4) method->nativeFunc;
} else {
/*
* The dexlist output shows the &DexCode.insns offset value, which
diff --git a/vm/Properties.c b/vm/Properties.c
index a9fe5e1..7758660 100644
--- a/vm/Properties.c
+++ b/vm/Properties.c
@@ -186,9 +186,11 @@
setProperty(propObj, put, "java.specification.version", "0.9");
#define OS_ARCH generic /* TODO: Use an "arch" header. */
- #define OS_ARCH_QUOTE(x) #x
+ #define OS_ARCH_QUOTE1(x) #x
+ #define OS_ARCH_QUOTE(x) OS_ARCH_QUOTE1(x)
setProperty(propObj, put, "os.arch", OS_ARCH_QUOTE(OS_ARCH));
#undef OS_ARCH
+ #undef OS_ARCH_QUOTE1
#undef OS_ARCH_QUOTE
setProperty(propObj, put, "os.name", info.sysname);
diff --git a/vm/SignalCatcher.c b/vm/SignalCatcher.c
index 550f777..495fbf2 100644
--- a/vm/SignalCatcher.c
+++ b/vm/SignalCatcher.c
@@ -192,6 +192,9 @@
sigemptyset(&mask);
sigaddset(&mask, SIGQUIT);
sigaddset(&mask, SIGUSR1);
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+ sigaddset(&mask, SIGUSR2);
+#endif
while (true) {
int rcvd;
@@ -237,6 +240,10 @@
logThreadStacks();
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+ dvmCompilerDumpStats();
+#endif
+
if (false) {
dvmLockMutex(&gDvm.jniGlobalRefLock);
dvmDumpReferenceTable(&gDvm.jniGlobalRefTable, "JNI global");
@@ -253,6 +260,11 @@
LOGI("SIGUSR1 forcing GC (no HPROF)\n");
dvmCollectGarbage(false);
#endif
+#if defined(WITH_JIT) && defined(WITH_JIT_TUNING)
+ } else if (rcvd == SIGUSR2) {
+ gDvmJit.printMe ^= true;
+ dvmCompilerDumpStats();
+#endif
} else {
LOGE("unexpected signal %d\n", rcvd);
}
@@ -260,4 +272,3 @@
return NULL;
}
-
diff --git a/vm/Thread.c b/vm/Thread.c
index 7116dfd..aa1b549 100644
--- a/vm/Thread.c
+++ b/vm/Thread.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Thread support.
*/
@@ -233,6 +234,16 @@
static void waitForThreadSuspend(Thread* self, Thread* thread);
static int getThreadPriorityFromSystem(void);
+/*
+ * The JIT needs to know if any thread is suspended. We do this by
+ * maintaining a global sum of all threads' suspend counts. All suspendCount
+ * updates should go through this after aquiring threadSuspendCountLock.
+ */
+static inline void dvmAddToThreadSuspendCount(int *pSuspendCount, int delta)
+{
+ *pSuspendCount += delta;
+ gDvm.sumThreadSuspendCount += delta;
+}
/*
* Initialize thread list and main thread's environment. We need to set
@@ -516,9 +527,15 @@
if (cc != 0) {
if (!dvmCheckSuspendPending(NULL)) {
/*
- * Could be we hit the window as the suspend or resume
- * was started (i.e. the lock has been grabbed but the
- * other thread hasn't yet set our "please suspend" flag).
+ * Could be that a resume-all is in progress, and something
+ * grabbed the CPU when the wakeup was broadcast. The thread
+ * performing the resume hasn't had a chance to release the
+ * thread suspend lock. (We release before the broadcast,
+ * so this should be a narrow window.)
+ *
+ * Could be we hit the window as a suspend was started,
+ * and the lock has been grabbed but the suspend counts
+ * haven't been incremented yet.
*
* Could be an unusual JNI thread-attach thing.
*
@@ -540,6 +557,7 @@
LOGE("threadid=%d: couldn't get thread-suspend lock (%s:%s),"
" bailing\n",
dvmThreadSelf()->threadId, who, getSuspendCauseStr(why));
+ /* threads are not suspended, thread dump could crash */
dvmDumpAllThreads(false);
dvmAbort();
}
@@ -604,6 +622,7 @@
LOGI("threadid=%d: killing leftover daemon threadid=%d [TODO]\n",
self->threadId, target->threadId);
+ LOGI(" name='%s'\n", dvmGetThreadName(target));
// TODO: suspend and/or kill the thread
// (at the very least, we can "rescind their JNI privileges")
@@ -988,6 +1007,12 @@
* This is mainly of use to ensure that we don't leak resources if, for
* example, a thread attaches itself to us with AttachCurrentThread and
* then exits without notifying the VM.
+ *
+ * We could do the detach here instead of aborting, but this will lead to
+ * portability problems. Other implementations do not do this check and
+ * will simply be unaware that the thread has exited, leading to resource
+ * leaks (and, if this is a non-daemon thread, an infinite hang when the
+ * VM tries to shut down).
*/
static void threadExitCheck(void* arg)
{
@@ -997,7 +1022,6 @@
assert(thread != NULL);
if (thread->status != THREAD_ZOMBIE) {
- /* TODO: instead of failing, we could call dvmDetachCurrentThread() */
LOGE("Native thread exited without telling us\n");
dvmAbort();
}
@@ -1244,9 +1268,13 @@
*/
dvmUnlockThreadList();
- if (pthread_create(&threadHandle, &threadAttr, interpThreadStart,
- newThread) != 0)
- {
+ int cc, oldStatus;
+ oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
+ cc = pthread_create(&threadHandle, &threadAttr, interpThreadStart,
+ newThread);
+ oldStatus = dvmChangeStatus(self, oldStatus);
+
+ if (cc != 0) {
/*
* Failure generally indicates that we have exceeded system
* resource limits. VirtualMachineError is probably too severe,
@@ -1291,7 +1319,8 @@
*
* The easiest way to deal with this is to prevent the new thread from
* running until the parent says it's okay. This results in the
- * following sequence of events for a "badly timed" GC:
+ * following (correct) sequence of events for a "badly timed" GC
+ * (where '-' is us, 'o' is the child, and '+' is some other thread):
*
* - call pthread_create()
* - lock thread list
@@ -1550,6 +1579,12 @@
}
bail:
+#if defined(WITH_JIT)
+ /* Remove this thread's suspendCount from global suspendCount sum */
+ lockThreadSuspendCount();
+ dvmAddToThreadSuspendCount(&self->suspendCount, -self->suspendCount);
+ unlockThreadSuspendCount();
+#endif
dvmReleaseTrackedAlloc(exception, self);
}
@@ -2126,7 +2161,7 @@
//assert(thread->handle != dvmJdwpGetDebugThread(gDvm.jdwpState));
lockThreadSuspendCount();
- thread->suspendCount++;
+ dvmAddToThreadSuspendCount(&thread->suspendCount, 1);
thread->dbgSuspendCount++;
LOG_THREAD("threadid=%d: suspend++, now=%d\n",
@@ -2155,7 +2190,7 @@
lockThreadSuspendCount();
if (thread->suspendCount > 0) {
- thread->suspendCount--;
+ dvmAddToThreadSuspendCount(&thread->suspendCount, -1);
thread->dbgSuspendCount--;
} else {
LOG_THREAD("threadid=%d: suspendCount already zero\n",
@@ -2193,7 +2228,7 @@
* though.
*/
lockThreadSuspendCount();
- self->suspendCount++;
+ dvmAddToThreadSuspendCount(&self->suspendCount, 1);
self->dbgSuspendCount++;
/*
@@ -2331,10 +2366,13 @@
*
* TODO: track basic stats about time required to suspend VM.
*/
+#define FIRST_SLEEP (250*1000) /* 0.25s */
+#define MORE_SLEEP (750*1000) /* 0.75s */
static void waitForThreadSuspend(Thread* self, Thread* thread)
{
const int kMaxRetries = 10;
- const int kSpinSleepTime = 750*1000; /* 0.75s */
+ int spinSleepTime = FIRST_SLEEP;
+ bool complained = false;
int sleepIter = 0;
int retryCount = 0;
@@ -2344,14 +2382,27 @@
if (sleepIter == 0) // get current time on first iteration
startWhen = dvmGetRelativeTimeUsec();
- if (!dvmIterativeSleep(sleepIter++, kSpinSleepTime, startWhen)) {
+#if defined (WITH_JIT)
+ /*
+ * If we're still waiting after the first timeout,
+ * unchain all translations.
+ */
+ if (gDvmJit.pJitEntryTable && retryCount > 0) {
+ LOGD("JIT unchain all attempt #%d",retryCount);
+ dvmJitUnchainAll();
+ }
+#endif
+
+ if (!dvmIterativeSleep(sleepIter++, spinSleepTime, startWhen)) {
LOGW("threadid=%d (h=%d): spin on suspend threadid=%d (handle=%d)\n",
self->threadId, (int)self->handle,
thread->threadId, (int)thread->handle);
dumpWedgedThread(thread);
+ complained = true;
// keep going; could be slow due to valgrind
sleepIter = 0;
+ spinSleepTime = MORE_SLEEP;
if (retryCount++ == kMaxRetries) {
LOGE("threadid=%d: stuck on threadid=%d, giving up\n",
@@ -2361,6 +2412,11 @@
}
}
}
+
+ if (complained) {
+ LOGW("threadid=%d: spin on suspend resolved\n", self->threadId);
+ //dvmDumpThread(thread, false); /* suspended, so dump is safe */
+ }
}
/*
@@ -2425,7 +2481,7 @@
thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState))
continue;
- thread->suspendCount++;
+ dvmAddToThreadSuspendCount(&thread->suspendCount, 1);
if (why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT)
thread->dbgSuspendCount++;
}
@@ -2497,10 +2553,12 @@
/* debugger events don't suspend JDWP thread */
if ((why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT) &&
thread->handle == dvmJdwpGetDebugThread(gDvm.jdwpState))
+ {
continue;
+ }
if (thread->suspendCount > 0) {
- thread->suspendCount--;
+ dvmAddToThreadSuspendCount(&thread->suspendCount, -1);
if (why == SUSPEND_FOR_DEBUG || why == SUSPEND_FOR_DEBUG_EVENT)
thread->dbgSuspendCount--;
} else {
@@ -2512,6 +2570,43 @@
dvmUnlockThreadList();
/*
+ * In some ways it makes sense to continue to hold the thread-suspend
+ * lock while we issue the wakeup broadcast. It allows us to complete
+ * one operation before moving on to the next, which simplifies the
+ * thread activity debug traces.
+ *
+ * This approach caused us some difficulty under Linux, because the
+ * condition variable broadcast not only made the threads runnable,
+ * but actually caused them to execute, and it was a while before
+ * the thread performing the wakeup had an opportunity to release the
+ * thread-suspend lock.
+ *
+ * This is a problem because, when a thread tries to acquire that
+ * lock, it times out after 3 seconds. If at some point the thread
+ * is told to suspend, the clock resets; but since the VM is still
+ * theoretically mid-resume, there's no suspend pending. If, for
+ * example, the GC was waking threads up while the SIGQUIT handler
+ * was trying to acquire the lock, we would occasionally time out on
+ * a busy system and SignalCatcher would abort.
+ *
+ * We now perform the unlock before the wakeup broadcast. The next
+ * suspend can't actually start until the broadcast completes and
+ * returns, because we're holding the thread-suspend-count lock, but the
+ * suspending thread is now able to make progress and we avoid the abort.
+ *
+ * (Technically there is a narrow window between when we release
+ * the thread-suspend lock and grab the thread-suspend-count lock.
+ * This could cause us to send a broadcast to threads with nonzero
+ * suspend counts, but this is expected and they'll all just fall
+ * right back to sleep. It's probably safe to grab the suspend-count
+ * lock before releasing thread-suspend, since we're still following
+ * the correct order of acquisition, but it feels weird.)
+ */
+
+ LOG_THREAD("threadid=%d: ResumeAll waking others\n", self->threadId);
+ unlockThreadSuspend();
+
+ /*
* Broadcast a notification to all suspended threads, some or all of
* which may choose to wake up. No need to wait for them.
*/
@@ -2520,8 +2615,6 @@
assert(cc == 0);
unlockThreadSuspendCount();
- unlockThreadSuspend();
-
LOG_THREAD("threadid=%d: ResumeAll complete\n", self->threadId);
}
@@ -2556,7 +2649,8 @@
}
assert(thread->suspendCount >= thread->dbgSuspendCount);
- thread->suspendCount -= thread->dbgSuspendCount;
+ dvmAddToThreadSuspendCount(&thread->suspendCount,
+ -thread->dbgSuspendCount);
thread->dbgSuspendCount = 0;
}
unlockThreadSuspendCount();
@@ -2989,9 +3083,9 @@
threadName, isDaemon ? " daemon" : "",
priority, thread->threadId, kStatusNames[thread->status]);
dvmPrintDebugMessage(target,
- " | group=\"%s\" sCount=%d dsCount=%d s=%c obj=%p\n",
+ " | group=\"%s\" sCount=%d dsCount=%d s=%c obj=%p self=%p\n",
groupName, thread->suspendCount, thread->dbgSuspendCount,
- thread->isSuspended ? 'Y' : 'N', thread->threadObj);
+ thread->isSuspended ? 'Y' : 'N', thread->threadObj, thread);
dvmPrintDebugMessage(target,
" | sysTid=%d nice=%d sched=%d/%d handle=%d\n",
thread->systemTid, getpriority(PRIO_PROCESS, thread->systemTid),
@@ -3218,9 +3312,15 @@
* GC helper functions
*/
+/*
+ * Add the contents of the registers from the interpreted call stack.
+ */
static void gcScanInterpStackReferences(Thread *thread)
{
const u4 *framePtr;
+#if WITH_EXTRA_GC_CHECKS > 1
+ bool first = true;
+#endif
framePtr = (const u4 *)thread->curFrame;
while (framePtr != NULL) {
@@ -3229,27 +3329,185 @@
saveArea = SAVEAREA_FROM_FP(framePtr);
method = saveArea->method;
- if (method != NULL) {
+ if (method != NULL && !dvmIsNativeMethod(method)) {
#ifdef COUNT_PRECISE_METHODS
/* the GC is running, so no lock required */
- if (!dvmIsNativeMethod(method)) {
- if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
- LOGI("Added %s.%s %p\n",
- method->clazz->descriptor, method->name, method);
- }
+ if (dvmPointerSetAddEntry(gDvm.preciseMethods, method))
+ LOGI("PGC: added %s.%s %p\n",
+ method->clazz->descriptor, method->name, method);
#endif
- int i;
- for (i = method->registersSize - 1; i >= 0; i--) {
- u4 rval = *framePtr++;
-//TODO: wrap markifobject in a macro that does pointer checks
- if (rval != 0 && (rval & 0x3) == 0) {
- dvmMarkIfObject((Object *)rval);
+#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);
+ if (pMap != NULL) {
+ /* found map, get registers for this address */
+ int addr = saveArea->xtra.currentPc - method->insns;
+ regVector = dvmRegisterMapGetLine(pMap, addr);
+ if (regVector == NULL) {
+ LOGW("PGC: map but no entry for %s.%s addr=0x%04x\n",
+ method->clazz->descriptor, method->name, addr);
+ } else {
+ LOGV("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.
+ *
+ * TODO: we should be able to remove this for production --
+ * no need to keep banging on the global.
+ */
+ if (gDvm.preciseGc) {
+ LOGV("PGC: no map for %s.%s\n",
+ method->clazz->descriptor, method->name);
+ }
+ regVector = NULL;
+ }
+
+ if (regVector == NULL) {
+ /* conservative scan */
+ for (i = method->registersSize - 1; i >= 0; i--) {
+ u4 rval = *framePtr++;
+ if (rval != 0 && (rval & 0x3) == 0) {
+ dvmMarkIfObject((Object *)rval);
+ }
+ }
+ } 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;
+ LOGVV("loaded bits: 0x%02x\n", bits & 0xff);
+ }
+
+ 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
+ {
+ dvmMarkObjectNonNull((Object *)rval);
+ }
+ } 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
+ }
+ }
+ dvmReleaseRegisterMapLine(pMap, regVector);
}
}
- /* else this is a break frame; nothing to mark.
+ /* 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;
+#endif
+
/* Don't fall into an infinite loop if things get corrupted.
*/
assert((uintptr_t)saveArea->prevFrame > (uintptr_t)framePtr ||
@@ -3354,4 +3612,3 @@
*/
gcScanAllThreads();
}
-
diff --git a/vm/Thread.h b/vm/Thread.h
index 9c15f9e..f1e5651 100644
--- a/vm/Thread.h
+++ b/vm/Thread.h
@@ -203,6 +203,11 @@
#ifdef WITH_JNI_STACK_CHECK
u4 stackCrc;
#endif
+
+#if WITH_EXTRA_GC_CHECKS > 1
+ /* PC, saved on every instruction; redundant with StackSaveArea */
+ const u2* currentPc2;
+#endif
} Thread;
/* start point for an internal thread; mimics pthread args */
@@ -250,6 +255,9 @@
SUSPEND_FOR_DEBUG_EVENT,
SUSPEND_FOR_STACK_DUMP,
SUSPEND_FOR_DEX_OPT,
+#if defined(WITH_JIT)
+ SUSPEND_FOR_JIT,
+#endif
} SuspendCause;
void dvmSuspendThread(Thread* thread);
void dvmSuspendSelf(bool jdwpActivity);
@@ -277,12 +285,11 @@
bool dvmCheckSuspendPending(Thread* self);
/*
- * Fast test for use in the interpreter. If our suspend count is nonzero,
- * do a more rigorous evaluation.
+ * Fast test for use in the interpreter. Returns "true" if our suspend
+ * count is nonzero.
*/
-INLINE void dvmCheckSuspendQuick(Thread* self) {
- if (self->suspendCount != 0)
- dvmCheckSuspendPending(self);
+INLINE bool dvmCheckSuspendQuick(Thread* self) {
+ return (self->suspendCount != 0);
}
/*
diff --git a/vm/alloc/Alloc.h b/vm/alloc/Alloc.h
index 0489db7..8bf4520 100644
--- a/vm/alloc/Alloc.h
+++ b/vm/alloc/Alloc.h
@@ -133,7 +133,7 @@
}
#ifdef WITH_EXTRA_OBJECT_VALIDATION
if (!dvmIsValidObject(obj)) {
- //abort();
+ //dvmAbort();
dvmThrowException("Ljava/lang/InternalError;",
"VM detected invalid object ptr");
return false;
@@ -142,7 +142,7 @@
#ifndef NDEBUG
/* check for heap corruption */
if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
- abort();
+ dvmAbort();
dvmThrowException("Ljava/lang/InternalError;",
"VM detected invalid object class ptr");
return false;
diff --git a/vm/alloc/DdmHeap.c b/vm/alloc/DdmHeap.c
index 78da6cd..f21a875 100644
--- a/vm/alloc/DdmHeap.c
+++ b/vm/alloc/DdmHeap.c
@@ -224,10 +224,18 @@
* allocation units used by the chunk.
*/
{
+ size_t needed = (((chunklen/ALLOCATION_UNIT_SIZE + 255) / 256) * 2);
size_t bytesLeft = ctx->bufLen - (size_t)(ctx->p - ctx->buf);
- if (bytesLeft < (((chunklen/ALLOCATION_UNIT_SIZE + 255) / 256) * 2)) {
+ if (bytesLeft < needed) {
flush_hpsg_chunk(ctx);
}
+
+ bytesLeft = ctx->bufLen - (size_t)(ctx->p - ctx->buf);
+ if (bytesLeft < needed) {
+ LOGW("chunk is too big to transmit (chunklen=%zd, %zd bytes)\n",
+ chunklen, needed);
+ return;
+ }
}
//TODO: notice when there's a gap and start a new heap, or at least a new range.
@@ -345,7 +353,12 @@
HPSG_WHAT_DISTINCT_OBJECTS = 1,
};
-#define HPSx_CHUNK_SIZE (4096 - 16)
+/*
+ * Maximum chunk size. Obtain this from the formula:
+ *
+ * (((maximum_heap_size / ALLOCATION_UNIT_SIZE) + 255) / 256) * 2
+ */
+#define HPSx_CHUNK_SIZE (16384 - 16)
void dlmalloc_walk_heap(void(*)(const void*, size_t, const void*, size_t, void*),void*);
diff --git a/vm/alloc/Heap.c b/vm/alloc/Heap.c
index e58a8a8..01bffa3 100644
--- a/vm/alloc/Heap.c
+++ b/vm/alloc/Heap.c
@@ -174,6 +174,7 @@
if (self != NULL) {
oldStatus = dvmChangeStatus(self, THREAD_VMWAIT);
} else {
+ LOGI("ODD: waiting on heap lock, no self\n");
oldStatus = -1; // shut up gcc
}
@@ -867,7 +868,10 @@
/* Set up the marking context.
*/
- dvmHeapBeginMarkStep();
+ if (!dvmHeapBeginMarkStep()) {
+ LOGE_HEAP("dvmHeapBeginMarkStep failed; aborting\n");
+ dvmAbort();
+ }
/* Mark the set of objects that are strongly reachable from the roots.
*/
diff --git a/vm/alloc/HeapWorker.c b/vm/alloc/HeapWorker.c
index b4a2d0e..e7a4d03 100644
--- a/vm/alloc/HeapWorker.c
+++ b/vm/alloc/HeapWorker.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* An async worker thread to handle certain heap operations that
* need to be done in a separate thread to avoid synchronization
@@ -342,12 +343,20 @@
/* Trim the heap if we were asked to. */
trimtime = gDvm.gcHeap->heapWorkerNextTrim;
if (trimtime.tv_sec != 0 && trimtime.tv_nsec != 0) {
- struct timeval now;
+ struct timespec now;
- gettimeofday(&now, NULL);
+#ifdef HAVE_TIMEDWAIT_MONOTONIC
+ clock_gettime(CLOCK_MONOTONIC, &now); // relative time
+#else
+ struct timeval tvnow;
+ gettimeofday(&tvnow, NULL); // absolute time
+ now.tv_sec = tvnow.tv_sec;
+ now.tv_nsec = tvnow.tv_usec * 1000;
+#endif
+
if (trimtime.tv_sec < now.tv_sec ||
(trimtime.tv_sec == now.tv_sec &&
- trimtime.tv_nsec <= now.tv_usec * 1000))
+ trimtime.tv_nsec <= now.tv_nsec))
{
size_t madvisedSizes[HEAP_SOURCE_MAX_HEAP_COUNT];
@@ -377,8 +386,13 @@
/* sleep until signaled */
if (timedwait) {
+#ifdef HAVE_TIMEDWAIT_MONOTONIC
+ cc = pthread_cond_timedwait_monotonic(&gDvm.heapWorkerCond,
+ &gDvm.heapWorkerLock, &trimtime);
+#else
cc = pthread_cond_timedwait(&gDvm.heapWorkerCond,
&gDvm.heapWorkerLock, &trimtime);
+#endif
assert(cc == 0 || cc == ETIMEDOUT || cc == EINTR);
} else {
cc = pthread_cond_wait(&gDvm.heapWorkerCond, &gDvm.heapWorkerLock);
@@ -494,9 +508,14 @@
} else {
struct timeval now;
+#ifdef HAVE_TIMEDWAIT_MONOTONIC
+ clock_gettime(CLOCK_MONOTONIC, &timeout);
+ timeout.tv_sec += timeoutSec;
+#else
gettimeofday(&now, NULL);
timeout.tv_sec = now.tv_sec + timeoutSec;
timeout.tv_nsec = now.tv_usec * 1000;
+#endif
dvmSignalHeapWorker(false);
}
gcHeap->heapWorkerNextTrim = timeout;
diff --git a/vm/alloc/MarkSweep.c b/vm/alloc/MarkSweep.c
index a0601d7..84349a9 100644
--- a/vm/alloc/MarkSweep.c
+++ b/vm/alloc/MarkSweep.c
@@ -22,6 +22,7 @@
#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
@@ -92,7 +93,7 @@
{
const Object **limit;
size_t size;
- int fd;
+ int fd, err;
/* Create a stack big enough for the worst possible case,
* where the heap is perfectly full of the smallest object.
@@ -104,14 +105,17 @@
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\n", size);
+ LOGE_GC("Could not create %d-byte ashmem mark stack: %s\n",
+ size, strerror(errno));
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\n", size);
+ LOGE_GC("Could not mmap %d-byte ashmem mark stack: %s\n",
+ size, strerror(err));
return false;
}
@@ -520,6 +524,17 @@
}
#endif
+#if WITH_OBJECT_HEADERS
+ if (ptr2chunk(obj)->scanGeneration == gGeneration) {
+ LOGE("object 0x%08x was already scanned this generation\n",
+ (uintptr_t)obj);
+ dvmAbort();
+ }
+ ptr2chunk(obj)->oldScanGeneration = ptr2chunk(obj)->scanGeneration;
+ ptr2chunk(obj)->scanGeneration = gGeneration;
+ ptr2chunk(obj)->scanCount++;
+#endif
+
/* Get and mark the class object for this particular instance.
*/
clazz = obj->clazz;
@@ -540,16 +555,9 @@
*/
return;
}
+
#if WITH_OBJECT_HEADERS
gMarkParent = obj;
- if (ptr2chunk(obj)->scanGeneration == gGeneration) {
- LOGE("object 0x%08x was already scanned this generation\n",
- (uintptr_t)obj);
- dvmAbort();
- }
- ptr2chunk(obj)->oldScanGeneration = ptr2chunk(obj)->scanGeneration;
- ptr2chunk(obj)->scanGeneration = gGeneration;
- ptr2chunk(obj)->scanCount++;
#endif
assert(dvmIsValidObject((Object *)clazz));
diff --git a/vm/analysis/CodeVerify.c b/vm/analysis/CodeVerify.c
index 8c5e8d2..a1862bb 100644
--- a/vm/analysis/CodeVerify.c
+++ b/vm/analysis/CodeVerify.c
@@ -72,9 +72,9 @@
static inline bool doVerboseLogging(const Method* meth) {
return false; /* COMMENT OUT to enable verbose debugging */
- const char* cd = "Lop_lshr;";
- const char* mn = "test";
- const char* sg = "(II)J";
+ const char* cd = "Landroid/net/http/Request;";
+ const char* mn = "readResponse";
+ const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
return (strcmp(meth->clazz->descriptor, cd) == 0 &&
dvmCompareNameDescriptorAndMethod(mn, sg, meth) == 0);
}
@@ -116,12 +116,13 @@
static void checkMergeTab(void);
static bool isInitMethod(const Method* meth);
static RegType getInvocationThis(const RegType* insnRegs,\
- const int insnRegCount, const DecodedInstruction* pDecInsn, bool* pOkay);
+ const int insnRegCount, const DecodedInstruction* pDecInsn,
+ VerifyError* pFailure);
static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,\
- u4 vsrc, RegType checkType, bool* pOkay);
-static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,\
+ u4 vsrc, RegType checkType, VerifyError* pFailure);
+static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,\
RegisterTable* regTable, UninitInstanceMap* uninitMap);
-static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,\
+static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,\
RegisterTable* regTable, RegType* workRegs, int insnIdx,
UninitInstanceMap* uninitMap, int* pStartGuess);
static ClassObject* findCommonSuperclass(ClassObject* c1, ClassObject* c2);
@@ -327,7 +328,7 @@
*/
static RegType primitiveTypeToRegType(PrimitiveType primType)
{
- struct {
+ static const struct {
RegType regType; /* type equivalent */
PrimitiveType primType; /* verification */
} convTab[] = {
@@ -545,9 +546,11 @@
/*
* Look up a class reference given as a simple string descriptor.
+ *
+ * If we can't find it, return a generic substitute when possible.
*/
static ClassObject* lookupClassByDescriptor(const Method* meth,
- const char* pDescriptor, bool* pOkay)
+ const char* pDescriptor, VerifyError* pFailure)
{
/*
* The javac compiler occasionally puts references to nonexistent
@@ -585,7 +588,7 @@
if (pDescriptor[1] != 'L' && pDescriptor[1] != '[') {
LOG_VFY("VFY: invalid char in signature in '%s'\n",
pDescriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
/*
@@ -607,17 +610,17 @@
} else {
/* We are looking at a primitive type. */
LOG_VFY("VFY: invalid char in signature in '%s'\n", pDescriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
if (clazz == NULL) {
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
}
if (dvmIsPrimitiveClass(clazz)) {
LOG_VFY("VFY: invalid use of primitive type '%s'\n", pDescriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
clazz = NULL;
}
@@ -634,7 +637,7 @@
* NOTE: this is also expected to verify the signature.
*/
static ClassObject* lookupSignatureClass(const Method* meth, const char** pSig,
- bool* pOkay)
+ VerifyError* pFailure)
{
const char* sig = *pSig;
const char* endp = sig;
@@ -645,7 +648,7 @@
;
if (*endp != ';') {
LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
return NULL;
}
@@ -657,7 +660,7 @@
*pSig = endp - 1; /* - 1 so that *pSig points at, not past, the ';' */
- return lookupClassByDescriptor(meth, typeStr, pOkay);
+ return lookupClassByDescriptor(meth, typeStr, pFailure);
}
/*
@@ -669,7 +672,7 @@
* NOTE: this is also expected to verify the signature.
*/
static ClassObject* lookupSignatureArrayClass(const Method* meth,
- const char** pSig, bool* pOkay)
+ const char** pSig, VerifyError* pFailure)
{
const char* sig = *pSig;
const char* endp = sig;
@@ -685,7 +688,7 @@
;
if (*endp != ';') {
LOG_VFY("VFY: bad signature component '%s' (missing ';')\n", sig);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
return NULL;
}
}
@@ -697,7 +700,7 @@
*pSig = endp;
- return lookupClassByDescriptor(meth, typeStr, pOkay);
+ return lookupClassByDescriptor(meth, typeStr, pFailure);
}
/*
@@ -713,7 +716,7 @@
{
DexParameterIterator iterator;
int actualArgs, expectedArgs, argStart;
- bool okay = true;
+ VerifyError failure = VERIFY_ERROR_NONE;
dexParameterIteratorInit(&iterator, &meth->prototype);
argStart = meth->registersSize - meth->insSize;
@@ -768,8 +771,8 @@
*/
{
ClassObject* clazz =
- lookupClassByDescriptor(meth, descriptor, &okay);
- if (!okay)
+ lookupClassByDescriptor(meth, descriptor, &failure);
+ if (!VERIFY_OK(failure))
goto bad_sig;
regTypes[argStart + actualArgs] = regTypeFromClass(clazz);
}
@@ -926,10 +929,10 @@
case 'L':
case '[':
{
- bool okay = true;
+ VerifyError failure = VERIFY_ERROR_NONE;
ClassObject* clazz =
- lookupClassByDescriptor(meth, descriptor, &okay);
- assert(okay);
+ lookupClassByDescriptor(meth, descriptor, &failure);
+ assert(VERIFY_OK(failure));
type = regTypeFromClass(clazz);
}
break;
@@ -1012,13 +1015,13 @@
* Widening conversions on integers and references are allowed, but
* narrowing conversions are not.
*
- * Returns the resolved method on success, NULL (and sets "*pOkay" to "false")
- * on failure.
+ * Returns the resolved method on success, NULL on failure (with *pFailure
+ * set appropriately).
*/
static Method* verifyInvocationArgs(const Method* meth, const RegType* insnRegs,
const int insnRegCount, const DecodedInstruction* pDecInsn,
UninitInstanceMap* uninitMap, MethodType methodType, bool isRange,
- bool isSuper, bool* pOkay)
+ bool isSuper, VerifyError* pFailure)
{
Method* resMethod;
char* sigOriginal = NULL;
@@ -1030,7 +1033,8 @@
if (methodType == METHOD_INTERFACE) {
resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
} else {
- resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType);
+ resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType,
+ pFailure);
}
if (resMethod == NULL) {
/* failed; print a meaningful failure message */
@@ -1051,7 +1055,7 @@
//char* curMethodDesc =
// dexProtoCopyMethodDescriptor(&meth->prototype);
- LOGE("Could not find method %s.%s, referenced from "
+ LOGI("Could not find method %s.%s, referenced from "
"method %s.%s\n",
dotMissingClass, methodName/*, methodDesc*/,
dotMethClass, meth->name/*, curMethodDesc*/);
@@ -1065,6 +1069,8 @@
dvmMethodTypeStr(methodType), pDecInsn->vB,
classDescriptor, methodName, methodDesc);
free(methodDesc);
+ if (VERIFY_OK(*pFailure)) /* not set for interface resolve */
+ *pFailure = VERIFY_ERROR_NO_METHOD;
goto fail;
}
@@ -1095,6 +1101,7 @@
(super == NULL) ? "-" : super->descriptor,
resMethod->name, desc);
free(desc);
+ *pFailure = VERIFY_ERROR_NO_METHOD;
goto fail;
}
}
@@ -1135,8 +1142,8 @@
RegType actualArgType;
actualArgType = getInvocationThis(insnRegs, insnRegCount, pDecInsn,
- pOkay);
- if (!*pOkay)
+ pFailure);
+ if (!VERIFY_OK(*pFailure))
goto fail;
if (regTypeIsUninitReference(actualArgType) && resMethod->name[0] != '<')
@@ -1176,12 +1183,12 @@
switch (*sig) {
case 'L':
{
- ClassObject* clazz = lookupSignatureClass(meth, &sig, pOkay);
- if (!*pOkay)
+ ClassObject* clazz = lookupSignatureClass(meth, &sig, pFailure);
+ if (!VERIFY_OK(*pFailure))
goto bad_sig;
verifyRegisterType(insnRegs, insnRegCount, getReg,
- regTypeFromClass(clazz), pOkay);
- if (!*pOkay) {
+ regTypeFromClass(clazz), pFailure);
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: bad arg %d (into %s)\n",
actualArgs, clazz->descriptor);
goto bad_sig;
@@ -1192,12 +1199,12 @@
case '[':
{
ClassObject* clazz =
- lookupSignatureArrayClass(meth, &sig, pOkay);
- if (!*pOkay)
+ lookupSignatureArrayClass(meth, &sig, pFailure);
+ if (!VERIFY_OK(*pFailure))
goto bad_sig;
verifyRegisterType(insnRegs, insnRegCount, getReg,
- regTypeFromClass(clazz), pOkay);
- if (!*pOkay) {
+ regTypeFromClass(clazz), pFailure);
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: bad arg %d (into %s)\n",
actualArgs, clazz->descriptor);
goto bad_sig;
@@ -1207,42 +1214,42 @@
break;
case 'Z':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeBoolean, pOkay);
+ kRegTypeBoolean, pFailure);
actualArgs++;
break;
case 'C':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeChar, pOkay);
+ kRegTypeChar, pFailure);
actualArgs++;
break;
case 'B':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeByte, pOkay);
+ kRegTypeByte, pFailure);
actualArgs++;
break;
case 'I':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeInteger, pOkay);
+ kRegTypeInteger, pFailure);
actualArgs++;
break;
case 'S':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeShort, pOkay);
+ kRegTypeShort, pFailure);
actualArgs++;
break;
case 'F':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeFloat, pOkay);
+ kRegTypeFloat, pFailure);
actualArgs++;
break;
case 'D':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeDoubleLo, pOkay);
+ kRegTypeDoubleLo, pFailure);
actualArgs += 2;
break;
case 'J':
verifyRegisterType(insnRegs, insnRegCount, getReg,
- kRegTypeLongLo, pOkay);
+ kRegTypeLongLo, pFailure);
actualArgs += 2;
break;
default:
@@ -1272,13 +1279,14 @@
if (resMethod != NULL) {
char* desc = dexProtoCopyMethodDescriptor(&resMethod->prototype);
LOG_VFY("VFY: rejecting call to %s.%s %s\n",
- resMethod->clazz->descriptor, resMethod->name, desc);
+ resMethod->clazz->descriptor, resMethod->name, desc);
free(desc);
}
fail:
free(sigOriginal);
- *pOkay = false;
+ if (*pFailure == VERIFY_ERROR_NONE)
+ *pFailure = VERIFY_ERROR_GENERIC;
return NULL;
}
@@ -1324,15 +1332,15 @@
/*
* Get the type of register N, verifying that the register is valid.
*
- * Sets "*pOkay" to false if the register number is out of range.
+ * Sets "*pFailure" appropriately if the register number is out of range.
*/
static inline RegType getRegisterType(const RegType* insnRegs,
- const int insnRegCount, u4 vsrc, bool* pOkay)
+ const int insnRegCount, u4 vsrc, VerifyError* pFailure)
{
RegType type;
if (vsrc >= (u4) insnRegCount) {
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
return kRegTypeUnknown;
} else {
return insnRegs[vsrc];
@@ -1341,21 +1349,21 @@
/*
* Get the value from a register, and cast it to a ClassObject. Sets
- * "pOkay" to false if something fails.
+ * "*pFailure" if something fails.
*
* This fails if the register holds an uninitialized class.
*
* If the register holds kRegTypeZero, this returns a NULL pointer.
*/
static ClassObject* getClassFromRegister(const RegType* insnRegs,
- const int insnRegCount, u4 vsrc, bool* pOkay)
+ const int insnRegCount, u4 vsrc, VerifyError* pFailure)
{
ClassObject* clazz = NULL;
RegType type;
/* get the element type of the array held in vsrc */
- type = getRegisterType(insnRegs, insnRegCount, vsrc, pOkay);
- if (!*pOkay)
+ type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
+ if (!VERIFY_OK(*pFailure))
goto bail;
/* if "always zero", we allow it to fail at runtime */
@@ -1365,12 +1373,12 @@
if (!regTypeIsReference(type)) {
LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
vsrc, type);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
if (regTypeIsUninitReference(type)) {
LOG_VFY("VFY: register %u holds uninitialized reference\n", vsrc);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
@@ -1391,27 +1399,28 @@
* and then return vC.
*/
static RegType getInvocationThis(const RegType* insnRegs,
- const int insnRegCount, const DecodedInstruction* pDecInsn, bool* pOkay)
+ const int insnRegCount, const DecodedInstruction* pDecInsn,
+ VerifyError* pFailure)
{
RegType thisType = kRegTypeUnknown;
if (pDecInsn->vA < 1) {
LOG_VFY("VFY: invoke lacks 'this'\n");
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
/* get the element type of the array held in vsrc */
- thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pOkay);
- if (!*pOkay) {
- LOG_VFY("VFY: failed to get this from register %u\n", pDecInsn->vC);
+ thisType = getRegisterType(insnRegs, insnRegCount, pDecInsn->vC, pFailure);
+ if (!VERIFY_OK(*pFailure)) {
+ LOG_VFY("VFY: failed to get 'this' from register %u\n", pDecInsn->vC);
goto bail;
}
if (!regTypeIsReference(thisType)) {
LOG_VFY("VFY: tried to get class from non-ref register v%d (type=%d)\n",
pDecInsn->vC, thisType);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
@@ -1424,10 +1433,10 @@
* "newType" is the "Lo" part of a 64-bit value, register N+1 will be
* set to "newType+1".
*
- * Sets "*pOkay" to false if the register number is out of range.
+ * Sets "*pFailure" if the register number is out of range.
*/
static void setRegisterType(RegType* insnRegs, const int insnRegCount,
- u4 vdst, RegType newType, bool* pOkay)
+ u4 vdst, RegType newType, VerifyError* pFailure)
{
//LOGD("set-reg v%u = %d\n", vdst, newType);
switch (newType) {
@@ -1443,7 +1452,7 @@
case kRegTypeFloat:
case kRegTypeZero:
if (vdst >= (u4) insnRegCount) {
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
} else {
insnRegs[vdst] = newType;
}
@@ -1451,7 +1460,7 @@
case kRegTypeLongLo:
case kRegTypeDoubleLo:
if (vdst+1 >= (u4) insnRegCount) {
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
} else {
insnRegs[vdst] = newType;
insnRegs[vdst+1] = newType+1;
@@ -1460,14 +1469,14 @@
case kRegTypeLongHi:
case kRegTypeDoubleHi:
/* should never set these explicitly */
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
case kRegTypeUninit:
default:
if (regTypeIsReference(newType)) {
if (vdst >= (u4) insnRegCount) {
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
insnRegs[vdst] = newType;
@@ -1490,7 +1499,7 @@
case kRegTypeConflict: // should only be set during a merge
LOG_VFY("Unexpected set type %d\n", newType);
assert(false);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -1509,10 +1518,10 @@
* interface, verify that the register implements checkType.
*/
static void verifyRegisterType(const RegType* insnRegs, const int insnRegCount,
- u4 vsrc, RegType checkType, bool* pOkay)
+ u4 vsrc, RegType checkType, VerifyError* pFailure)
{
if (vsrc >= (u4) insnRegCount) {
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
return;
}
@@ -1531,7 +1540,7 @@
if (!canConvertTo1nr(srcType, checkType)) {
LOG_VFY("VFY: register1 v%u type %d, wanted %d\n",
vsrc, srcType, checkType);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
break;
case kRegTypeLongLo:
@@ -1539,15 +1548,15 @@
if (vsrc+1 >= (u4) insnRegCount) {
LOG_VFY("VFY: register2 v%u out of range (%d)\n",
vsrc, insnRegCount);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
} else if (insnRegs[vsrc+1] != srcType+1) {
LOG_VFY("VFY: register2 v%u-%u values %d,%d\n",
vsrc, vsrc+1, insnRegs[vsrc], insnRegs[vsrc+1]);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
} else if (!canConvertTo2(srcType, checkType)) {
LOG_VFY("VFY: register2 v%u type %d, wanted %d\n",
vsrc, srcType, checkType);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
break;
@@ -1559,7 +1568,7 @@
case kRegTypeConflict:
/* should never be checking for these explicitly */
assert(false);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
return;
case kRegTypeUninit:
default:
@@ -1567,23 +1576,23 @@
if (!regTypeIsReference(checkType)) {
LOG_VFY("VFY: unexpected check type %d\n", checkType);
assert(false);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
if (regTypeIsUninitReference(checkType)) {
LOG_VFY("VFY: uninitialized ref not expected as reg check\n");
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
/* make sure srcType is initialized reference or always-NULL */
if (!regTypeIsReference(srcType)) {
LOG_VFY("VFY: register1 v%u type %d, wanted ref\n", vsrc, srcType);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
if (regTypeIsUninitReference(srcType)) {
LOG_VFY("VFY: register1 v%u holds uninitialized ref\n", vsrc);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
/* if the register isn't Zero, make sure it's an instance of check */
@@ -1605,14 +1614,14 @@
{
LOG_VFY("VFY: %s does not implement %s\n",
srcClass->descriptor, checkClass->descriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
*/
} else {
if (!dvmInstanceof(srcClass, checkClass)) {
LOG_VFY("VFY: %s is not instance of %s\n",
srcClass->descriptor, checkClass->descriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
}
}
@@ -1625,10 +1634,10 @@
* "insnRegCount" to encompass the result register.
*/
static void setResultRegisterType(RegType* insnRegs, const int insnRegCount,
- RegType newType, bool* pOkay)
+ RegType newType, VerifyError* pFailure)
{
setRegisterType(insnRegs, insnRegCount + kExtraRegs,
- RESULT_REGISTER(insnRegCount), newType, pOkay);
+ RESULT_REGISTER(insnRegCount), newType, pFailure);
}
@@ -1639,7 +1648,7 @@
* must be marked as initialized.
*/
static void markRefsAsInitialized(RegType* insnRegs, int insnRegCount,
- UninitInstanceMap* uninitMap, RegType uninitType, bool* pOkay)
+ UninitInstanceMap* uninitMap, RegType uninitType, VerifyError* pFailure)
{
ClassObject* clazz;
RegType initType;
@@ -1649,7 +1658,7 @@
if (clazz == NULL) {
LOGE("VFY: unable to find type=0x%x (idx=%d)\n",
uninitType, regTypeToUninitIndex(uninitType));
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
return;
}
initType = regTypeFromClass(clazz);
@@ -1748,9 +1757,10 @@
*
* For category 2 values, "type" must be the "low" half of the value.
*
- * Sets "*pOkay" to false if not.
+ * Sets "*pFailure" if something looks wrong.
*/
-static void checkTypeCategory(RegType type, TypeCategory cat, bool* pOkay)
+static void checkTypeCategory(RegType type, TypeCategory cat,
+ VerifyError* pFailure)
{
switch (cat) {
case kTypeCategory1nr:
@@ -1767,7 +1777,7 @@
case kRegTypeInteger:
break;
default:
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
break;
@@ -1778,19 +1788,19 @@
case kRegTypeDoubleLo:
break;
default:
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
break;
case kTypeCategoryRef:
if (type != kRegTypeZero && !regTypeIsReference(type))
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
default:
assert(false);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -1802,10 +1812,10 @@
* Does not verify that "typel" is in fact the low part of a 64-bit
* register pair.
*/
-static void checkWidePair(RegType typel, RegType typeh, bool* pOkay)
+static void checkWidePair(RegType typel, RegType typeh, VerifyError* pFailure)
{
if ((typeh != typel+1))
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
/*
@@ -1816,15 +1826,15 @@
* "vsrc" values are checked against this.
*/
static void copyRegister1(RegType* insnRegs, int insnRegCount, u4 vdst,
- u4 vsrc, TypeCategory cat, bool* pOkay)
+ u4 vsrc, TypeCategory cat, VerifyError* pFailure)
{
- RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pOkay);
- if (*pOkay)
- checkTypeCategory(type, cat, pOkay);
- if (*pOkay)
- setRegisterType(insnRegs, insnRegCount, vdst, type, pOkay);
+ RegType type = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
+ if (VERIFY_OK(*pFailure))
+ checkTypeCategory(type, cat, pFailure);
+ if (VERIFY_OK(*pFailure))
+ setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
- if (!*pOkay) {
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: copy1 v%u<-v%u type=%d cat=%d\n", vdst, vsrc, type, cat);
}
}
@@ -1834,18 +1844,18 @@
* "vsrc" to "vdst". This copies both halves of the register.
*/
static void copyRegister2(RegType* insnRegs, int insnRegCount, u4 vdst,
- u4 vsrc, bool* pOkay)
+ u4 vsrc, VerifyError* pFailure)
{
- RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pOkay);
- RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pOkay);
- if (*pOkay) {
- checkTypeCategory(typel, kTypeCategory2, pOkay);
- checkWidePair(typel, typeh, pOkay);
+ RegType typel = getRegisterType(insnRegs, insnRegCount, vsrc, pFailure);
+ RegType typeh = getRegisterType(insnRegs, insnRegCount, vsrc+1, pFailure);
+ if (VERIFY_OK(*pFailure)) {
+ checkTypeCategory(typel, kTypeCategory2, pFailure);
+ checkWidePair(typel, typeh, pFailure);
}
- if (*pOkay)
- setRegisterType(insnRegs, insnRegCount, vdst, typel, pOkay);
+ if (VERIFY_OK(*pFailure))
+ setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
- if (!*pOkay) {
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: copy2 v%u<-v%u type=%d/%d\n", vdst, vsrc, typel, typeh);
}
}
@@ -1858,21 +1868,21 @@
* because that would affect the test on "vdst" as well.
*/
static void copyResultRegister1(RegType* insnRegs, const int insnRegCount,
- u4 vdst, TypeCategory cat, bool* pOkay)
+ u4 vdst, TypeCategory cat, VerifyError* pFailure)
{
RegType type;
u4 vsrc;
vsrc = RESULT_REGISTER(insnRegCount);
- type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pOkay);
- if (*pOkay)
- checkTypeCategory(type, cat, pOkay);
- if (*pOkay) {
- setRegisterType(insnRegs, insnRegCount, vdst, type, pOkay);
+ type = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pFailure);
+ if (VERIFY_OK(*pFailure))
+ checkTypeCategory(type, cat, pFailure);
+ if (VERIFY_OK(*pFailure)) {
+ setRegisterType(insnRegs, insnRegCount, vdst, type, pFailure);
insnRegs[vsrc] = kRegTypeUnknown;
}
- if (!*pOkay) {
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: copyRes1 v%u<-v%u cat=%d type=%d\n",
vdst, vsrc, cat, type);
}
@@ -1886,25 +1896,27 @@
* because that would affect the test on "vdst" as well.
*/
static void copyResultRegister2(RegType* insnRegs, const int insnRegCount,
- u4 vdst, bool* pOkay)
+ u4 vdst, VerifyError* pFailure)
{
RegType typel, typeh;
u4 vsrc;
vsrc = RESULT_REGISTER(insnRegCount);
- typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc, pOkay);
- typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1, pOkay);
- if (*pOkay) {
- checkTypeCategory(typel, kTypeCategory2, pOkay);
- checkWidePair(typel, typeh, pOkay);
+ typel = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc,
+ pFailure);
+ typeh = getRegisterType(insnRegs, insnRegCount + kExtraRegs, vsrc+1,
+ pFailure);
+ if (VERIFY_OK(*pFailure)) {
+ checkTypeCategory(typel, kTypeCategory2, pFailure);
+ checkWidePair(typel, typeh, pFailure);
}
- if (*pOkay) {
- setRegisterType(insnRegs, insnRegCount, vdst, typel, pOkay);
+ if (VERIFY_OK(*pFailure)) {
+ setRegisterType(insnRegs, insnRegCount, vdst, typel, pFailure);
insnRegs[vsrc] = kRegTypeUnknown;
insnRegs[vsrc+1] = kRegTypeUnknown;
}
- if (!*pOkay) {
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: copyRes2 v%u<-v%u type=%d/%d\n",
vdst, vsrc, typel, typeh);
}
@@ -1916,10 +1928,10 @@
*/
static void checkUnop(RegType* insnRegs, const int insnRegCount,
DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
- bool* pOkay)
+ VerifyError* pFailure)
{
- verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pOkay);
- setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pOkay);
+ verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
+ setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
}
/*
@@ -1929,6 +1941,13 @@
*
* Assumes we've already validated reg1/reg2.
*
+ * TODO: consider generalizing this. The key principle is that the
+ * result of a bitwise operation can only be as wide as the widest of
+ * the operands. You can safely AND/OR/XOR two chars together and know
+ * you still have a char, so it's reasonable for the compiler or "dx"
+ * to skip the int-to-char instruction. (We need to do this for boolean
+ * because there is no int-to-boolean operation.)
+ *
* Returns true if both args are Boolean, Zero, or One.
*/
static bool upcastBooleanOp(RegType* insnRegs, const int insnRegCount,
@@ -1958,10 +1977,10 @@
*/
static void checkLitop(RegType* insnRegs, const int insnRegCount,
DecodedInstruction* pDecInsn, RegType dstType, RegType srcType,
- bool checkBooleanOp, bool* pOkay)
+ bool checkBooleanOp, VerifyError* pFailure)
{
- verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pOkay);
- if (*pOkay && checkBooleanOp) {
+ verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType, pFailure);
+ if (VERIFY_OK(*pFailure) && checkBooleanOp) {
assert(dstType == kRegTypeInteger);
/* check vB with the call, then check the constant manually */
if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vB)
@@ -1970,7 +1989,7 @@
dstType = kRegTypeBoolean;
}
}
- setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pOkay);
+ setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
}
/*
@@ -1980,16 +1999,18 @@
*/
static void checkBinop(RegType* insnRegs, const int insnRegCount,
DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
- RegType srcType2, bool checkBooleanOp, bool* pOkay)
+ RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
{
- verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1, pOkay);
- verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2, pOkay);
- if (*pOkay && checkBooleanOp) {
+ verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType1,
+ pFailure);
+ verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vC, srcType2,
+ pFailure);
+ if (VERIFY_OK(*pFailure) && checkBooleanOp) {
assert(dstType == kRegTypeInteger);
if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vB, pDecInsn->vC))
dstType = kRegTypeBoolean;
}
- setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pOkay);
+ setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
}
/*
@@ -1998,16 +2019,135 @@
*/
static void checkBinop2addr(RegType* insnRegs, const int insnRegCount,
DecodedInstruction* pDecInsn, RegType dstType, RegType srcType1,
- RegType srcType2, bool checkBooleanOp, bool* pOkay)
+ RegType srcType2, bool checkBooleanOp, VerifyError* pFailure)
{
- verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1, pOkay);
- verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2, pOkay);
- if (*pOkay && checkBooleanOp) {
+ verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vA, srcType1,
+ pFailure);
+ verifyRegisterType(insnRegs, insnRegCount, pDecInsn->vB, srcType2,
+ pFailure);
+ if (VERIFY_OK(*pFailure) && checkBooleanOp) {
assert(dstType == kRegTypeInteger);
if (upcastBooleanOp(insnRegs, insnRegCount, pDecInsn->vA, pDecInsn->vB))
dstType = kRegTypeBoolean;
}
- setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pOkay);
+ setRegisterType(insnRegs, insnRegCount, pDecInsn->vA, dstType, pFailure);
+}
+
+/*
+ * Treat right-shifting as a narrowing conversion when possible.
+ *
+ * For example, right-shifting an int 24 times results in a value that can
+ * be treated as a byte.
+ *
+ * Things get interesting when contemplating sign extension. Right-
+ * shifting an integer by 16 yields a value that can be represented in a
+ * "short" but not a "char", but an unsigned right shift by 16 yields a
+ * value that belongs in a char rather than a short. (Consider what would
+ * happen if the result of the shift were cast to a char or short and then
+ * cast back to an int. If sign extension, or the lack thereof, causes
+ * a change in the 32-bit representation, then the conversion was lossy.)
+ *
+ * A signed right shift by 17 on an integer results in a short. An unsigned
+ * right shfit by 17 on an integer results in a posshort, which can be
+ * assigned to a short or a char.
+ *
+ * An unsigned right shift on a short can actually expand the result into
+ * a 32-bit integer. For example, 0xfffff123 >>> 8 becomes 0x00fffff1,
+ * which can't be represented in anything smaller than an int.
+ *
+ * javac does not generate code that takes advantage of this, but some
+ * of the code optimizers do. It's generally a peephole optimization
+ * that replaces a particular sequence, e.g. (bipush 24, ishr, i2b) is
+ * replaced by (bipush 24, ishr). Knowing that shifting a short 8 times
+ * to the right yields a byte is really more than we need to handle the
+ * code that's out there, but support is not much more complex than just
+ * handling integer.
+ *
+ * Right-shifting never yields a boolean value.
+ *
+ * Returns the new register type.
+ */
+static RegType adjustForRightShift(RegType* workRegs, const int insnRegCount,
+ int reg, unsigned int shiftCount, bool isUnsignedShift,
+ VerifyError* pFailure)
+{
+ RegType srcType = getRegisterType(workRegs, insnRegCount, reg, pFailure);
+ RegType newType;
+
+ /* no-op */
+ if (shiftCount == 0)
+ return srcType;
+
+ /* safe defaults */
+ if (isUnsignedShift)
+ newType = kRegTypeInteger;
+ else
+ newType = srcType;
+
+ if (shiftCount >= 32) {
+ LOG_VFY("Got unexpectedly large shift count %u\n", shiftCount);
+ /* fail? */
+ return newType;
+ }
+
+ switch (srcType) {
+ case kRegTypeInteger: /* 32-bit signed value */
+ case kRegTypeFloat: /* (allowed; treat same as int) */
+ if (isUnsignedShift) {
+ if (shiftCount > 24)
+ newType = kRegTypePosByte;
+ else if (shiftCount >= 16)
+ newType = kRegTypeChar;
+ } else {
+ if (shiftCount >= 24)
+ newType = kRegTypeByte;
+ else if (shiftCount >= 16)
+ newType = kRegTypeShort;
+ }
+ break;
+ case kRegTypeShort: /* 16-bit signed value */
+ if (isUnsignedShift) {
+ /* default (kRegTypeInteger) is correct */
+ } else {
+ if (shiftCount >= 8)
+ newType = kRegTypeByte;
+ }
+ break;
+ case kRegTypePosShort: /* 15-bit unsigned value */
+ if (shiftCount >= 8)
+ newType = kRegTypePosByte;
+ break;
+ case kRegTypeChar: /* 16-bit unsigned value */
+ if (shiftCount > 8)
+ newType = kRegTypePosByte;
+ break;
+ case kRegTypeByte: /* 8-bit signed value */
+ /* defaults (u=kRegTypeInteger / s=srcType) are correct */
+ break;
+ case kRegTypePosByte: /* 7-bit unsigned value */
+ /* always use newType=srcType */
+ newType = srcType;
+ break;
+ case kRegTypeZero: /* 1-bit unsigned value */
+ case kRegTypeOne:
+ case kRegTypeBoolean:
+ /* unnecessary? */
+ newType = kRegTypeZero;
+ break;
+ default:
+ /* long, double, references; shouldn't be here! */
+ assert(false);
+ break;
+ }
+
+ if (newType != srcType) {
+ LOGVV("narrowing: %d(%d) --> %d to %d\n",
+ shiftCount, isUnsignedShift, srcType, newType);
+ } else {
+ LOGVV("not narrowed: %d(%d) --> %d\n",
+ shiftCount, isUnsignedShift, srcType);
+ }
+ return newType;
}
@@ -2329,28 +2469,28 @@
* allow it to be uninitialized if this is an "<init>" method and the field
* is declared within the "objType" class.
*
- * Returns an InstField on success, returns NULL and sets "*pOkay" to false
+ * Returns an InstField on success, returns NULL and sets "*pFailure"
* on failure.
*/
static InstField* getInstField(const Method* meth,
const UninitInstanceMap* uninitMap, RegType objType, int fieldIdx,
- bool* pOkay)
+ VerifyError* pFailure)
{
InstField* instField = NULL;
ClassObject* objClass;
bool mustBeLocal = false;
if (!regTypeIsReference(objType)) {
- LOG_VFY("VFY: attempt to access field of non-reference type %d\n",
+ LOG_VFY("VFY: attempt to access field in non-reference type %d\n",
objType);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
- instField = dvmOptResolveInstField(meth->clazz, fieldIdx);
+ instField = dvmOptResolveInstField(meth->clazz, fieldIdx, pFailure);
if (instField == NULL) {
LOG_VFY("VFY: unable to resolve instance field %u\n", fieldIdx);
- *pOkay = false;
+ assert(!VERIFY_OK(*pFailure));
goto bail;
}
@@ -2367,7 +2507,7 @@
if (regTypeIsUninitReference(objType)) {
if (!isInitMethod(meth) || meth->clazz != objClass) {
LOG_VFY("VFY: attempt to access field via uninitialized ref\n");
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
mustBeLocal = true;
@@ -2377,7 +2517,7 @@
LOG_VFY("VFY: invalid field access (field %s.%s, through %s ref)\n",
instField->field.clazz->descriptor, instField->field.name,
objClass->descriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_NO_FIELD;
goto bail;
}
@@ -2388,7 +2528,7 @@
{
LOG_VFY("VFY: invalid constructor field access (field %s in %s)\n",
instField->field.name, objClass->descriptor);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
goto bail;
}
}
@@ -2400,15 +2540,15 @@
/*
* Look up a static field.
*
- * Returns a StaticField on success, returns NULL and sets "*pOkay" to false
+ * Returns a StaticField on success, returns NULL and sets "*pFailure"
* on failure.
*/
static StaticField* getStaticField(const Method* meth, int fieldIdx,
- bool* pOkay)
+ VerifyError* pFailure)
{
StaticField* staticField;
- staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx);
+ staticField = dvmOptResolveStaticField(meth->clazz, fieldIdx, pFailure);
if (staticField == NULL) {
DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
const DexFieldId* pFieldId;
@@ -2418,8 +2558,7 @@
LOG_VFY("VFY: unable to resolve static field %u (%s) in %s\n", fieldIdx,
dexStringById(pDexFile, pFieldId->nameIdx),
dexStringByTypeIdx(pDexFile, pFieldId->classIdx));
-
- *pOkay = false;
+ assert(!VERIFY_OK(*pFailure));
goto bail;
}
@@ -2431,10 +2570,10 @@
* If "field" is marked "final", make sure this is the either <clinit>
* or <init> as appropriate.
*
- * Sets "*pOkay" to false on failure.
+ * Sets "*pFailure" on failure.
*/
static void checkFinalFieldAccess(const Method* meth, const Field* field,
- bool* pOkay)
+ VerifyError* pFailure)
{
if (!dvmIsFinalField(field))
return;
@@ -2443,21 +2582,15 @@
if (meth->clazz != field->clazz) {
LOG_VFY_METH(meth, "VFY: can't modify final field %s.%s\n",
field->clazz->descriptor, field->name);
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_ACCESS_FIELD;
return;
}
/*
- * The EMMA code coverage tool generates a static method that
- * modifies a private static final field. The method is only
- * called by <clinit>, so the code is reasonable if not quite
- * kosher. (Attempting to *compile* code that does something
- * like that will earn you a quick thumbs-down from javac.)
- *
- * The verifier in another popular VM doesn't complain about this,
- * so we're going to allow classes to modify their own static
- * final fields outside of class initializers. Further testing
- * showed that modifications to instance fields are also allowed.
+ * The VM spec descriptions of putfield and putstatic say that
+ * IllegalAccessError is only thrown when the instructions appear
+ * outside the declaring class. Our earlier attempts to restrict
+ * final field modification to constructors are, therefore, wrong.
*/
#if 0
/* make sure we're in the right kind of constructor */
@@ -2465,13 +2598,13 @@
if (!isClassInitMethod(meth)) {
LOG_VFY_METH(meth,
"VFY: can't modify final static field outside <clinit>\n");
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
} else {
if (!isInitMethod(meth)) {
LOG_VFY_METH(meth,
"VFY: can't modify final field outside <init>\n");
- *pOkay = false;
+ *pFailure = VERIFY_ERROR_GENERIC;
}
}
#endif
@@ -2480,19 +2613,19 @@
/*
* Make sure that the register type is suitable for use as an array index.
*
- * Sets "*pOkay" to false if not.
+ * Sets "*pFailure" if not.
*/
static void checkArrayIndexType(const Method* meth, RegType regType,
- bool* pOkay)
+ VerifyError* pFailure)
{
- if (*pOkay) {
+ if (VERIFY_OK(*pFailure)) {
/*
* The 1nr types are interchangeable at this level. We could
* do something special if we can definitively identify it as a
* float, but there's no real value in doing so.
*/
- checkTypeCategory(regType, kTypeCategory1nr, pOkay);
- if (!*pOkay) {
+ checkTypeCategory(regType, kTypeCategory1nr, pFailure);
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY_METH(meth, "Invalid reg type for array index (%d)\n",
regType);
}
@@ -2560,11 +2693,14 @@
* Returns NULL if no matching exception handler can be found, or if the
* exception is not a subclass of Throwable.
*/
-static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx)
+static ClassObject* getCaughtExceptionType(const Method* meth, int insnIdx,
+ VerifyError* pFailure)
{
+ VerifyError localFailure;
const DexCode* pCode;
DexFile* pDexFile;
ClassObject* commonSuper = NULL;
+ bool foundPossibleHandler = false;
u4 handlersSize;
u4 offset;
u4 i;
@@ -2593,16 +2729,22 @@
if (handler->address == (u4) insnIdx) {
ClassObject* clazz;
+ foundPossibleHandler = true;
if (handler->typeIdx == kDexNoIndex)
clazz = gDvm.classJavaLangThrowable;
else
- clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx);
+ clazz = dvmOptResolveClass(meth->clazz, handler->typeIdx,
+ &localFailure);
if (clazz == NULL) {
LOG_VFY("VFY: unable to resolve exception class %u (%s)\n",
handler->typeIdx,
dexStringByTypeIdx(pDexFile, handler->typeIdx));
+ /* TODO: do we want to keep going? If we don't fail
+ * this we run the risk of having a non-Throwable
+ * introduced at runtime. However, that won't pass
+ * an instanceof test, so is essentially harmless. */
} else {
if (commonSuper == NULL)
commonSuper = clazz;
@@ -2616,8 +2758,12 @@
}
if (commonSuper == NULL) {
+ /* no catch blocks, or no catches with classes we can find */
LOG_VFY_METH(meth,
"VFY: unable to find exception handler at addr 0x%x\n", insnIdx);
+ *pFailure = VERIFY_ERROR_GENERIC;
+ } else {
+ // TODO: verify the class is an instance of Throwable?
}
return commonSuper;
@@ -2732,7 +2878,7 @@
static void verifyFilledNewArrayRegs(const Method* meth,
const RegType* insnRegs, const int insnRegCount,
const DecodedInstruction* pDecInsn, ClassObject* resClass, bool isRange,
- bool* pOkay)
+ VerifyError* pFailure)
{
u4 argCount = pDecInsn->vA;
RegType expectedType;
@@ -2761,8 +2907,9 @@
else
getReg = pDecInsn->arg[ui];
- verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType, pOkay);
- if (!*pOkay) {
+ verifyRegisterType(insnRegs, insnRegCount, getReg, expectedType,
+ pFailure);
+ if (!VERIFY_OK(*pFailure)) {
LOG_VFY("VFY: filled-new-array arg %u(%u) not valid\n", ui, getReg);
return;
}
@@ -2771,6 +2918,121 @@
/*
+ * Replace an instruction with "throw-verification-error". This allows us to
+ * defer error reporting until the code path is first used.
+ *
+ * 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
+ * in "insnFlags".
+ *
+ * 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,
+ int insnIdx, VerifyError failure)
+{
+ const u2* oldInsns = meth->insns + insnIdx;
+ u2 oldInsn = *oldInsns;
+ bool result = false;
+
+ dvmMakeCodeReadWrite(meth);
+
+ //LOGD(" was 0x%04x\n", oldInsn);
+ u2* newInsns = (u2*) meth->insns + insnIdx;
+
+ /*
+ * Generate the new instruction out of the old.
+ *
+ * First, make sure this is an instruction we're expecting to stomp on.
+ */
+ switch (oldInsn & 0xff) {
+ case OP_CONST_CLASS: // insn[1] == class ref, 2 bytes
+ case OP_CHECK_CAST:
+ case OP_INSTANCE_OF:
+ case OP_NEW_INSTANCE:
+ case OP_NEW_ARRAY:
+
+ case OP_FILLED_NEW_ARRAY: // insn[1] == class ref, 3 bytes
+ case OP_FILLED_NEW_ARRAY_RANGE:
+
+ case OP_IGET: // insn[1] == field ref, 2 bytes
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IGET_WIDE:
+ case OP_IGET_OBJECT:
+ case OP_IPUT:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ case OP_SGET:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ case OP_SGET_WIDE:
+ case OP_SGET_OBJECT:
+ case OP_SPUT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ case OP_SPUT_WIDE:
+ case OP_SPUT_OBJECT:
+
+ case OP_INVOKE_VIRTUAL: // insn[1] == method ref, 3 bytes
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ break;
+ default:
+ /* could handle this in a generic way, but this is probably safer */
+ LOG_VFY("GLITCH: verifier asked to replace opcode 0x%02x\n",
+ oldInsn & 0xff);
+ goto bail;
+ }
+
+ /* write a NOP over the third code unit, if necessary */
+ int width = dvmInsnGetWidth(insnFlags, insnIdx);
+ switch (width) {
+ case 2:
+ /* nothing to do */
+ break;
+ case 3:
+ newInsns[2] = OP_NOP;
+ break;
+ default:
+ /* whoops */
+ LOGE("ERROR: stomped a %d-unit instruction with a verifier error\n",
+ width);
+ dvmAbort();
+ }
+
+ /* encode the opcode, with the failure code in the high byte */
+ newInsns[0] = OP_THROW_VERIFICATION_ERROR | (failure << 8);
+
+ result = true;
+
+bail:
+ dvmMakeCodeReadOnly(meth);
+ return result;
+}
+
+
+/*
* ===========================================================================
* Entry point and driver loop
* ===========================================================================
@@ -2779,7 +3041,7 @@
/*
* Entry point for the detailed code-flow analysis.
*/
-bool dvmVerifyCodeFlow(const Method* meth, InsnFlags* insnFlags,
+bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
UninitInstanceMap* uninitMap)
{
bool result = false;
@@ -2806,9 +3068,13 @@
if (gDvm.classJavaLangString == NULL)
gDvm.classJavaLangString =
dvmFindSystemClassNoInit("Ljava/lang/String;");
- if (gDvm.classJavaLangThrowable == NULL)
+ if (gDvm.classJavaLangThrowable == NULL) {
gDvm.classJavaLangThrowable =
dvmFindSystemClassNoInit("Ljava/lang/Throwable;");
+ gDvm.offJavaLangThrowable_cause =
+ dvmFindFieldOffset(gDvm.classJavaLangThrowable,
+ "cause", "Ljava/lang/Throwable;");
+ }
if (gDvm.classJavaLangObject == NULL)
gDvm.classJavaLangObject =
dvmFindSystemClassNoInit("Ljava/lang/Object;");
@@ -2929,7 +3195,7 @@
* instruction if a register contains an uninitialized instance created
* by that same instrutcion.
*/
-static bool doCodeVerification(const Method* meth, InsnFlags* insnFlags,
+static bool doCodeVerification(Method* meth, InsnFlags* insnFlags,
RegisterTable* regTable, UninitInstanceMap* uninitMap)
{
const int insnsSize = dvmGetMethodInsnsSize(meth);
@@ -3087,10 +3353,14 @@
dvmInsnSetChanged(insnFlags, insnIdx, false);
}
- if (DEAD_CODE_SCAN) {
+ if (DEAD_CODE_SCAN && !IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
/*
- * Scan for dead code. There's nothing "evil" about dead code, but it
- * indicates a flaw somewhere down the line, possibly in the verifier.
+ * Scan for dead code. There's nothing "evil" about dead code
+ * (besides the wasted space), but it indicates a flaw somewhere
+ * down the line, possibly in the verifier.
+ *
+ * If we've rewritten "always throw" instructions into the stream,
+ * we are almost certainly going to have some dead code.
*/
int deadStart = -1;
for (insnIdx = 0; insnIdx < insnsSize;
@@ -3156,8 +3426,11 @@
* if execution at that point needs to be (re-)evaluated. Register changes
* are merged into "regTypes" at the target addresses. Does not set or
* clear any other flags in "insnFlags".
+ *
+ * This may alter meth->insns if we need to replace an instruction with
+ * throw-verification-error.
*/
-static bool verifyInstruction(const Method* meth, InsnFlags* insnFlags,
+static bool verifyInstruction(Method* meth, InsnFlags* insnFlags,
RegisterTable* regTable, RegType* workRegs, int insnIdx,
UninitInstanceMap* uninitMap, int* pStartGuess)
{
@@ -3194,14 +3467,14 @@
RegType tmpType;
DecodedInstruction decInsn;
bool justSetResult = false;
- bool okay = true;
+ VerifyError failure = VERIFY_ERROR_NONE;
#ifndef NDEBUG
memset(&decInsn, 0x81, sizeof(decInsn));
#endif
dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
- const int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
+ int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
/*
* Make a copy of the previous register state. If the instruction
@@ -3229,7 +3502,7 @@
*/
if (decInsn.vA != 0) {
LOG_VFY("VFY: encountered data table in instruction stream\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
}
break;
@@ -3237,18 +3510,18 @@
case OP_MOVE_FROM16:
case OP_MOVE_16:
copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
- kTypeCategory1nr, &okay);
+ kTypeCategory1nr, &failure);
break;
case OP_MOVE_WIDE:
case OP_MOVE_WIDE_FROM16:
case OP_MOVE_WIDE_16:
- copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &okay);
+ copyRegister2(workRegs, insnRegCount, decInsn.vA, decInsn.vB, &failure);
break;
case OP_MOVE_OBJECT:
case OP_MOVE_OBJECT_FROM16:
case OP_MOVE_OBJECT_16:
copyRegister1(workRegs, insnRegCount, decInsn.vA, decInsn.vB,
- kTypeCategoryRef, &okay);
+ kTypeCategoryRef, &failure);
break;
/*
@@ -3264,14 +3537,14 @@
*/
case OP_MOVE_RESULT:
copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
- kTypeCategory1nr, &okay);
+ kTypeCategory1nr, &failure);
break;
case OP_MOVE_RESULT_WIDE:
- copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &okay);
+ copyResultRegister2(workRegs, insnRegCount, decInsn.vA, &failure);
break;
case OP_MOVE_RESULT_OBJECT:
copyResultRegister1(workRegs, insnRegCount, decInsn.vA,
- kTypeCategoryRef, &okay);
+ kTypeCategoryRef, &failure);
break;
case OP_MOVE_EXCEPTION:
@@ -3284,71 +3557,75 @@
* "resClass" will hold the closest common superclass of all
* exceptions that can be handled here.
*/
- resClass = getCaughtExceptionType(meth, insnIdx);
+ resClass = getCaughtExceptionType(meth, insnIdx, &failure);
if (resClass == NULL) {
- okay = false;
+ assert(!VERIFY_OK(failure));
} else {
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(resClass), &okay);
+ regTypeFromClass(resClass), &failure);
}
break;
case OP_RETURN_VOID:
- okay = checkConstructorReturn(meth, workRegs, insnRegCount);
- if (okay && getMethodReturnType(meth) != kRegTypeUnknown) {
+ if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
+ failure = VERIFY_ERROR_GENERIC;
+ } else if (getMethodReturnType(meth) != kRegTypeUnknown) {
LOG_VFY("VFY: return-void not expected\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
}
break;
case OP_RETURN:
- okay = checkConstructorReturn(meth, workRegs, insnRegCount);
- if (okay) {
+ if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
+ failure = VERIFY_ERROR_GENERIC;
+ } else {
/* check the method signature */
RegType returnType = getMethodReturnType(meth);
- checkTypeCategory(returnType, kTypeCategory1nr, &okay);
- if (!okay)
+ checkTypeCategory(returnType, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure))
LOG_VFY("VFY: return-32 not expected\n");
/* check the register contents */
returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
- checkTypeCategory(returnType, kTypeCategory1nr, &okay);
- if (!okay)
+ &failure);
+ checkTypeCategory(returnType, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure))
LOG_VFY("VFY: return-32 on invalid register v%d\n", decInsn.vA);
}
break;
case OP_RETURN_WIDE:
- okay = checkConstructorReturn(meth, workRegs, insnRegCount);
- if (okay) {
+ if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
+ failure = VERIFY_ERROR_GENERIC;
+ } else {
RegType returnType, returnTypeHi;
/* check the method signature */
returnType = getMethodReturnType(meth);
- checkTypeCategory(returnType, kTypeCategory2, &okay);
- if (!okay)
+ checkTypeCategory(returnType, kTypeCategory2, &failure);
+ if (!VERIFY_OK(failure))
LOG_VFY("VFY: return-wide not expected\n");
/* check the register contents */
returnType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
+ &failure);
returnTypeHi = getRegisterType(workRegs, insnRegCount,
- decInsn.vA +1, &okay);
- if (okay) {
- checkTypeCategory(returnType, kTypeCategory2, &okay);
- checkWidePair(returnType, returnTypeHi, &okay);
+ decInsn.vA +1, &failure);
+ if (VERIFY_OK(failure)) {
+ checkTypeCategory(returnType, kTypeCategory2, &failure);
+ checkWidePair(returnType, returnTypeHi, &failure);
}
- if (!okay) {
+ if (!VERIFY_OK(failure)) {
LOG_VFY("VFY: return-wide on invalid register pair v%d\n",
decInsn.vA);
}
}
break;
case OP_RETURN_OBJECT:
- okay = checkConstructorReturn(meth, workRegs, insnRegCount);
- if (okay) {
+ if (!checkConstructorReturn(meth, workRegs, insnRegCount)) {
+ failure = VERIFY_ERROR_GENERIC;
+ } else {
RegType returnType = getMethodReturnType(meth);
- checkTypeCategory(returnType, kTypeCategoryRef, &okay);
- if (!okay) {
+ checkTypeCategory(returnType, kTypeCategoryRef, &failure);
+ if (!VERIFY_OK(failure)) {
LOG_VFY("VFY: return-object not expected\n");
break;
}
@@ -3371,16 +3648,17 @@
declClass = regTypeInitializedReferenceToClass(returnType);
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vA, &okay);
- if (!okay)
+ decInsn.vA, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL) {
if (!dvmIsInterfaceClass(declClass) &&
!dvmInstanceof(resClass, declClass))
{
- LOG_VFY("VFY: returning %s, declared %s\n",
- resClass->descriptor, declClass->descriptor);
- okay = false;
+ LOG_VFY("VFY: returning %s (cl=%p), declared %s (cl=%p)\n",
+ resClass->descriptor, resClass->classLoader,
+ declClass->descriptor, declClass->classLoader);
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -3392,12 +3670,12 @@
case OP_CONST:
/* could be boolean, int, float, or a null reference */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- dvmDetermineCat1Const((s4)decInsn.vB), &okay);
+ dvmDetermineCat1Const((s4)decInsn.vB), &failure);
break;
case OP_CONST_HIGH16:
/* could be boolean, int, float, or a null reference */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- dvmDetermineCat1Const((s4) decInsn.vB << 16), &okay);
+ dvmDetermineCat1Const((s4) decInsn.vB << 16), &failure);
break;
case OP_CONST_WIDE_16:
case OP_CONST_WIDE_32:
@@ -3405,36 +3683,38 @@
case OP_CONST_WIDE_HIGH16:
/* could be long or double; default to long and allow conversion */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- kRegTypeLongLo, &okay);
+ kRegTypeLongLo, &failure);
break;
case OP_CONST_STRING:
case OP_CONST_STRING_JUMBO:
assert(gDvm.classJavaLangString != NULL);
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(gDvm.classJavaLangString), &okay);
+ regTypeFromClass(gDvm.classJavaLangString), &failure);
break;
case OP_CONST_CLASS:
assert(gDvm.classJavaLangClass != NULL);
/* make sure we can resolve the class; access check is important */
- resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve const-class %d (%s) in %s\n",
decInsn.vB, badClassDesc, meth->clazz->descriptor);
- okay = false;
+ assert(failure != VERIFY_ERROR_GENERIC);
} else {
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(gDvm.classJavaLangClass), &okay);
+ regTypeFromClass(gDvm.classJavaLangClass), &failure);
}
break;
case OP_MONITOR_ENTER:
case OP_MONITOR_EXIT:
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (okay && !regTypeIsReference(tmpType)) {
- LOG_VFY("VFY: monitor op on non-object\n");
- okay = false;
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (VERIFY_OK(failure)) {
+ if (!regTypeIsReference(tmpType)) {
+ LOG_VFY("VFY: monitor op on non-object\n");
+ failure = VERIFY_ERROR_GENERIC;
+ }
}
break;
@@ -3447,86 +3727,88 @@
* If it fails, an exception is thrown, which we deal with later
* by ignoring the update to decInsn.vA when branching to a handler.
*/
- resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve check-cast %d (%s) in %s\n",
decInsn.vB, badClassDesc, meth->clazz->descriptor);
- okay = false;
+ assert(failure != VERIFY_ERROR_GENERIC);
} else {
RegType origType;
origType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
if (!regTypeIsReference(origType)) {
LOG_VFY("VFY: check-cast on non-reference in v%u\n",decInsn.vA);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(resClass), &okay);
+ regTypeFromClass(resClass), &failure);
}
break;
case OP_INSTANCE_OF:
/* make sure we're checking a reference type */
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &okay);
- if (!okay)
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
if (!regTypeIsReference(tmpType)) {
LOG_VFY("VFY: vB not a reference (%d)\n", tmpType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
/* make sure we can resolve the class; access check is important */
- resClass = dvmOptResolveClass(meth->clazz, decInsn.vC);
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve instanceof %d (%s) in %s\n",
decInsn.vC, badClassDesc, meth->clazz->descriptor);
- okay = false;
+ assert(failure != VERIFY_ERROR_GENERIC);
} else {
/* result is boolean */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- kRegTypeBoolean, &okay);
+ kRegTypeBoolean, &failure);
}
break;
case OP_ARRAY_LENGTH:
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
- if (!okay)
+ decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL && !dvmIsArrayClass(resClass)) {
LOG_VFY("VFY: array-length on non-array\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeInteger,
- &okay);
+ &failure);
break;
case OP_NEW_INSTANCE:
- /*
- * We can check for interface and abstract classes here, but we
- * can't reject them. We can ask the optimizer to replace the
- * instructions with a magic "always throw InstantiationError"
- * instruction. (Not enough bytes to sub in a method call.)
- */
- resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve new-instance %d (%s) in %s\n",
decInsn.vB, badClassDesc, meth->clazz->descriptor);
- okay = false;
+ assert(failure != VERIFY_ERROR_GENERIC);
} else {
RegType uninitType;
+ /* can't create an instance of an interface or abstract class */
+ if (dvmIsAbstractClass(resClass) || dvmIsInterfaceClass(resClass)) {
+ LOG_VFY("VFY: new-instance on interface or abstract class %s\n",
+ resClass->descriptor);
+ failure = VERIFY_ERROR_INSTANTIATION;
+ break;
+ }
+
/* add resolved class to uninit map if not already there */
int uidx = dvmSetUninitInstance(uninitMap, insnIdx, resClass);
assert(uidx >= 0);
@@ -3541,50 +3823,50 @@
/* add the new uninitialized reference to the register ste */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- uninitType, &okay);
+ uninitType, &failure);
}
break;
case OP_NEW_ARRAY:
- resClass = dvmOptResolveClass(meth->clazz, decInsn.vC);
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vC, &failure);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vC);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve new-array %d (%s) in %s\n",
decInsn.vC, badClassDesc, meth->clazz->descriptor);
- okay = false;
+ assert(failure != VERIFY_ERROR_GENERIC);
} else if (!dvmIsArrayClass(resClass)) {
LOG_VFY("VFY: new-array on non-array class\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
} else {
/* make sure "size" register is valid type */
verifyRegisterType(workRegs, insnRegCount, decInsn.vB,
- kRegTypeInteger, &okay);
+ kRegTypeInteger, &failure);
/* set register type to array class */
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(resClass), &okay);
+ regTypeFromClass(resClass), &failure);
}
break;
case OP_FILLED_NEW_ARRAY:
case OP_FILLED_NEW_ARRAY_RANGE:
- resClass = dvmOptResolveClass(meth->clazz, decInsn.vB);
+ resClass = dvmOptResolveClass(meth->clazz, decInsn.vB, &failure);
if (resClass == NULL) {
const char* badClassDesc = dexStringByTypeIdx(pDexFile, decInsn.vB);
dvmLogUnableToResolveClass(badClassDesc, meth);
LOG_VFY("VFY: unable to resolve filled-array %d (%s) in %s\n",
decInsn.vB, badClassDesc, meth->clazz->descriptor);
- okay = false;
+ assert(failure != VERIFY_ERROR_GENERIC);
} else if (!dvmIsArrayClass(resClass)) {
LOG_VFY("VFY: filled-new-array on non-array class\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
} else {
bool isRange = (decInsn.opCode == OP_FILLED_NEW_ARRAY_RANGE);
/* check the arguments to the instruction */
verifyFilledNewArrayRegs(meth, workRegs, insnRegCount, &decInsn,
- resClass, isRange, &okay);
+ resClass, isRange, &failure);
/* filled-array result goes into "result" register */
setResultRegisterType(workRegs, insnRegCount,
- regTypeFromClass(resClass), &okay);
+ regTypeFromClass(resClass), &failure);
justSetResult = true;
}
break;
@@ -3592,38 +3874,38 @@
case OP_CMPL_FLOAT:
case OP_CMPG_FLOAT:
verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeFloat,
- &okay);
+ &failure);
verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeFloat,
- &okay);
+ &failure);
setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
- &okay);
+ &failure);
break;
case OP_CMPL_DOUBLE:
case OP_CMPG_DOUBLE:
verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeDoubleLo,
- &okay);
+ &failure);
verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeDoubleLo,
- &okay);
+ &failure);
setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
- &okay);
+ &failure);
break;
case OP_CMP_LONG:
verifyRegisterType(workRegs, insnRegCount, decInsn.vB, kRegTypeLongLo,
- &okay);
+ &failure);
verifyRegisterType(workRegs, insnRegCount, decInsn.vC, kRegTypeLongLo,
- &okay);
+ &failure);
setRegisterType(workRegs, insnRegCount, decInsn.vA, kRegTypeBoolean,
- &okay);
+ &failure);
break;
case OP_THROW:
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vA, &okay);
- if (okay && resClass != NULL) {
+ decInsn.vA, &failure);
+ if (VERIFY_OK(failure) && resClass != NULL) {
if (!dvmInstanceof(resClass, gDvm.classJavaLangThrowable)) {
LOG_VFY("VFY: thrown class %s not instanceof Throwable\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
}
}
break;
@@ -3638,7 +3920,7 @@
case OP_SPARSE_SWITCH:
/* verify that vAA is an integer, or can be converted to one */
verifyRegisterType(workRegs, insnRegCount, decInsn.vA,
- kRegTypeInteger, &okay);
+ kRegTypeInteger, &failure);
break;
case OP_FILL_ARRAY_DATA:
@@ -3649,8 +3931,8 @@
/* Similar to the verification done for APUT */
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vA, &okay);
- if (!okay)
+ decInsn.vA, &failure);
+ if (!VERIFY_OK(failure))
break;
/* resClass can be null if the reg type is Zero */
@@ -3663,7 +3945,7 @@
{
LOG_VFY("VFY: invalid fill-array-data on %s\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -3678,7 +3960,7 @@
arrayData = insns + (insns[1] | (((s4)insns[2]) << 16));
if (arrayData[0] != kArrayDataSignature) {
LOG_VFY("VFY: invalid magic for array-data\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -3712,7 +3994,7 @@
if (arrayData[1] != elemWidth) {
LOG_VFY("VFY: array-data size mismatch (%d vs %d)\n",
arrayData[1], elemWidth);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
}
}
break;
@@ -3723,9 +4005,11 @@
RegType type1, type2;
bool tmpResult;
- type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB, &okay);
- if (!okay)
+ type1 = getRegisterType(workRegs, insnRegCount, decInsn.vA,
+ &failure);
+ type2 = getRegisterType(workRegs, insnRegCount, decInsn.vB,
+ &failure);
+ if (!VERIFY_OK(failure))
break;
/* both references? */
@@ -3733,9 +4017,9 @@
break;
/* both category-1nr? */
- checkTypeCategory(type1, kTypeCategory1nr, &okay);
- checkTypeCategory(type2, kTypeCategory1nr, &okay);
- if (!okay) {
+ checkTypeCategory(type1, kTypeCategory1nr, &failure);
+ checkTypeCategory(type2, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure)) {
LOG_VFY("VFY: args to if-eq/if-ne must both be refs or cat1\n");
break;
}
@@ -3745,43 +4029,43 @@
case OP_IF_GE:
case OP_IF_GT:
case OP_IF_LE:
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (!okay)
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (!VERIFY_OK(failure))
break;
- checkTypeCategory(tmpType, kTypeCategory1nr, &okay);
- if (!okay) {
+ checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure)) {
LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
break;
}
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB,&okay);
- if (!okay)
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
- checkTypeCategory(tmpType, kTypeCategory1nr, &okay);
- if (!okay) {
+ checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure)) {
LOG_VFY("VFY: args to 'if' must be cat-1nr\n");
break;
}
break;
case OP_IF_EQZ:
case OP_IF_NEZ:
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (!okay)
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (!VERIFY_OK(failure))
break;
if (regTypeIsReference(tmpType))
break;
- checkTypeCategory(tmpType, kTypeCategory1nr, &okay);
- if (!okay)
+ checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure))
LOG_VFY("VFY: expected cat-1 arg to if\n");
break;
case OP_IF_LTZ:
case OP_IF_GEZ:
case OP_IF_GTZ:
case OP_IF_LEZ:
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (!okay)
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (!VERIFY_OK(failure))
break;
- checkTypeCategory(tmpType, kTypeCategory1nr, &okay);
- if (!okay)
+ checkTypeCategory(tmpType, kTypeCategory1nr, &failure);
+ if (!VERIFY_OK(failure))
LOG_VFY("VFY: expected cat-1 arg to if\n");
break;
@@ -3805,14 +4089,14 @@
RegType srcType, indexType;
indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
- &okay);
- checkArrayIndexType(meth, indexType, &okay);
- if (!okay)
+ &failure);
+ checkArrayIndexType(meth, indexType, &failure);
+ if (!VERIFY_OK(failure))
break;
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
- if (!okay)
+ decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL) {
/* verify the class */
@@ -3821,7 +4105,7 @@
{
LOG_VFY("VFY: invalid aget-1nr target %s\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -3833,13 +4117,13 @@
LOG_VFY("VFY: invalid aget-1nr, array type=%d with"
" inst type=%d (on %s)\n",
srcType, tmpType, resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- tmpType, &okay);
+ tmpType, &failure);
}
break;
@@ -3848,14 +4132,14 @@
RegType dstType, indexType;
indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
- &okay);
- checkArrayIndexType(meth, indexType, &okay);
- if (!okay)
+ &failure);
+ checkArrayIndexType(meth, indexType, &failure);
+ if (!VERIFY_OK(failure))
break;
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
- if (!okay)
+ decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL) {
/* verify the class */
@@ -3864,7 +4148,7 @@
{
LOG_VFY("VFY: invalid aget-wide target %s\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -3880,7 +4164,7 @@
LOG_VFY("VFY: invalid aget-wide on %s\n",
resClass->descriptor);
dstType = kRegTypeUnknown;
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
} else {
@@ -3893,7 +4177,7 @@
dstType = kRegTypeLongLo;
}
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- dstType, &okay);
+ dstType, &failure);
}
break;
@@ -3902,15 +4186,15 @@
RegType dstType, indexType;
indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
- &okay);
- checkArrayIndexType(meth, indexType, &okay);
- if (!okay)
+ &failure);
+ checkArrayIndexType(meth, indexType, &failure);
+ if (!VERIFY_OK(failure))
break;
/* get the class of the array we're pulling an object from */
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
- if (!okay)
+ decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL) {
ClassObject* elementClass;
@@ -3918,7 +4202,7 @@
assert(resClass != NULL);
if (!dvmIsArrayClass(resClass)) {
LOG_VFY("VFY: aget-object on non-array class\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
assert(resClass->elementClass != NULL);
@@ -3938,7 +4222,7 @@
} else {
LOG_VFY("VFY: aget-object on non-ref array class (%s)\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -3954,7 +4238,7 @@
dstType = kRegTypeZero;
}
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- dstType, &okay);
+ dstType, &failure);
}
break;
case OP_APUT:
@@ -3977,24 +4261,24 @@
RegType srcType, dstType, indexType;
indexType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
- &okay);
- checkArrayIndexType(meth, indexType, &okay);
- if (!okay)
+ &failure);
+ checkArrayIndexType(meth, indexType, &failure);
+ if (!VERIFY_OK(failure))
break;
/* make sure the source register has the correct type */
srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
+ &failure);
if (!canConvertTo1nr(srcType, tmpType)) {
LOG_VFY("VFY: invalid reg type %d on aput instr (need %d)\n",
srcType, tmpType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
- if (!okay)
+ decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
/* resClass can be null if the reg type is Zero */
@@ -4005,7 +4289,7 @@
resClass->elementClass->primitiveType == PRIM_NOT)
{
LOG_VFY("VFY: invalid aput-1nr on %s\n", resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4017,31 +4301,31 @@
if (!checkFieldArrayStore1nr(tmpType, dstType)) {
LOG_VFY("VFY: invalid aput-1nr on %s (inst=%d dst=%d)\n",
resClass->descriptor, tmpType, dstType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
break;
case OP_APUT_WIDE:
tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
- &okay);
- checkArrayIndexType(meth, tmpType, &okay);
- if (!okay)
+ &failure);
+ checkArrayIndexType(meth, tmpType, &failure);
+ if (!VERIFY_OK(failure))
break;
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (okay) {
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (VERIFY_OK(failure)) {
RegType typeHi =
- getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &okay);
- checkTypeCategory(tmpType, kTypeCategory2, &okay);
- checkWidePair(tmpType, typeHi, &okay);
+ getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
+ checkTypeCategory(tmpType, kTypeCategory2, &failure);
+ checkWidePair(tmpType, typeHi, &failure);
}
- if (!okay)
+ if (!VERIFY_OK(failure))
break;
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
- if (!okay)
+ decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL) {
/* verify the class and try to refine "dstType" */
@@ -4050,7 +4334,7 @@
{
LOG_VFY("VFY: invalid aput-wide on %s\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4062,22 +4346,22 @@
default:
LOG_VFY("VFY: invalid aput-wide on %s\n",
resClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
break;
case OP_APUT_OBJECT:
tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vC,
- &okay);
- checkArrayIndexType(meth, tmpType, &okay);
- if (!okay)
+ &failure);
+ checkArrayIndexType(meth, tmpType, &failure);
+ if (!VERIFY_OK(failure))
break;
/* get the ref we're storing; Zero is okay, Uninit is not */
resClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vA, &okay);
- if (!okay)
+ decInsn.vA, &failure);
+ if (!VERIFY_OK(failure))
break;
if (resClass != NULL) {
ClassObject* arrayClass;
@@ -4089,14 +4373,14 @@
* null pointer exception).
*/
arrayClass = getClassFromRegister(workRegs, insnRegCount,
- decInsn.vB, &okay);
+ decInsn.vB, &failure);
if (arrayClass != NULL) {
/* see if the array holds a compatible type */
if (!dvmIsArrayClass(arrayClass)) {
LOG_VFY("VFY: invalid aput-object on %s\n",
arrayClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4121,7 +4405,7 @@
if (elementClass->primitiveType != PRIM_NOT) {
LOG_VFY("VFY: invalid aput-object of %s into %s\n",
resClass->descriptor, arrayClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -4150,12 +4434,12 @@
RegType objType, fieldType;
objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
instField = getInstField(meth, uninitMap, objType, decInsn.vC,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
/* make sure the field's type is compatible with expectation */
@@ -4166,11 +4450,12 @@
LOG_VFY("VFY: invalid iget-1nr of %s.%s (inst=%d field=%d)\n",
instField->field.clazz->descriptor,
instField->field.name, tmpType, fieldType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
- setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType, &okay);
+ setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
+ &failure);
}
break;
case OP_IGET_WIDE:
@@ -4181,12 +4466,12 @@
RegType objType;
objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
instField = getInstField(meth, uninitMap, objType, decInsn.vC,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
/* check the type, which should be prim */
switch (instField->field.signature[0]) {
@@ -4201,12 +4486,12 @@
instField->field.clazz->descriptor,
instField->field.name);
dstType = kRegTypeUnknown;
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
- if (okay) {
+ if (VERIFY_OK(failure)) {
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- dstType, &okay);
+ dstType, &failure);
}
}
break;
@@ -4217,25 +4502,25 @@
RegType objType;
objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
instField = getInstField(meth, uninitMap, objType, decInsn.vC,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
fieldClass = getFieldClass(meth, &instField->field);
if (fieldClass == NULL) {
/* class not found or primitive type */
LOG_VFY("VFY: unable to recover field class from '%s'\n",
instField->field.signature);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
- if (okay) {
+ if (VERIFY_OK(failure)) {
assert(!dvmIsPrimitiveClass(fieldClass));
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(fieldClass), &okay);
+ regTypeFromClass(fieldClass), &failure);
}
}
break;
@@ -4260,26 +4545,34 @@
ClassObject* fieldClass;
InstField* instField;
- /* make sure the source register has the correct type */
srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
+ &failure);
+
+ /*
+ * javac generates synthetic functions that write byte values
+ * into boolean fields.
+ */
+ if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
+ srcType = kRegTypeBoolean;
+
+ /* make sure the source register has the correct type */
if (!canConvertTo1nr(srcType, tmpType)) {
LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
srcType, tmpType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
instField = getInstField(meth, uninitMap, objType, decInsn.vC,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
- checkFinalFieldAccess(meth, &instField->field, &okay);
- if (!okay)
+ checkFinalFieldAccess(meth, &instField->field, &failure);
+ if (!VERIFY_OK(failure))
break;
/* get type of field we're storing into */
@@ -4290,34 +4583,34 @@
LOG_VFY("VFY: invalid iput-1nr of %s.%s (inst=%d field=%d)\n",
instField->field.clazz->descriptor,
instField->field.name, tmpType, fieldType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
break;
case OP_IPUT_WIDE:
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (okay) {
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (VERIFY_OK(failure)) {
RegType typeHi =
- getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &okay);
- checkTypeCategory(tmpType, kTypeCategory2, &okay);
- checkWidePair(tmpType, typeHi, &okay);
+ getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
+ checkTypeCategory(tmpType, kTypeCategory2, &failure);
+ checkWidePair(tmpType, typeHi, &failure);
}
- if (okay) {
+ if (VERIFY_OK(failure)) {
ClassObject* fieldClass;
InstField* instField;
RegType objType;
objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
instField = getInstField(meth, uninitMap, objType, decInsn.vC,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
- checkFinalFieldAccess(meth, &instField->field, &okay);
- if (!okay)
+ checkFinalFieldAccess(meth, &instField->field, &failure);
+ if (!VERIFY_OK(failure))
break;
/* check the type, which should be prim */
@@ -4330,7 +4623,7 @@
LOG_VFY("VFY: invalid iput-wide of %s.%s\n",
instField->field.clazz->descriptor,
instField->field.name);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -4343,34 +4636,34 @@
RegType objType, valueType;
objType = getRegisterType(workRegs, insnRegCount, decInsn.vB,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
instField = getInstField(meth, uninitMap, objType, decInsn.vC,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
- checkFinalFieldAccess(meth, &instField->field, &okay);
- if (!okay)
+ checkFinalFieldAccess(meth, &instField->field, &failure);
+ if (!VERIFY_OK(failure))
break;
fieldClass = getFieldClass(meth, &instField->field);
if (fieldClass == NULL) {
LOG_VFY("VFY: unable to recover field class from '%s'\n",
instField->field.signature);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
if (!regTypeIsReference(valueType)) {
LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
decInsn.vA, instField->field.name,
fieldClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
if (valueType != kRegTypeZero) {
@@ -4378,7 +4671,7 @@
if (valueClass == NULL) {
LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
decInsn.vA);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
/* allow if field is any interface or field is base class */
@@ -4389,7 +4682,7 @@
valueClass->descriptor, fieldClass->descriptor,
instField->field.clazz->descriptor,
instField->field.name);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -4416,8 +4709,8 @@
StaticField* staticField;
RegType fieldType;
- staticField = getStaticField(meth, decInsn.vB, &okay);
- if (!okay)
+ staticField = getStaticField(meth, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
/*
@@ -4433,11 +4726,12 @@
LOG_VFY("VFY: invalid sget-1nr of %s.%s (inst=%d actual=%d)\n",
staticField->field.clazz->descriptor,
staticField->field.name, tmpType, fieldType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
- setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType, &okay);
+ setRegisterType(workRegs, insnRegCount, decInsn.vA, tmpType,
+ &failure);
}
break;
case OP_SGET_WIDE:
@@ -4445,8 +4739,8 @@
StaticField* staticField;
RegType dstType;
- staticField = getStaticField(meth, decInsn.vB, &okay);
- if (!okay)
+ staticField = getStaticField(meth, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
/* check the type, which should be prim */
switch (staticField->field.signature[0]) {
@@ -4461,12 +4755,12 @@
staticField->field.clazz->descriptor,
staticField->field.name);
dstType = kRegTypeUnknown;
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
- if (okay) {
+ if (VERIFY_OK(failure)) {
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- dstType, &okay);
+ dstType, &failure);
}
}
break;
@@ -4475,23 +4769,23 @@
StaticField* staticField;
ClassObject* fieldClass;
- staticField = getStaticField(meth, decInsn.vB, &okay);
- if (!okay)
+ staticField = getStaticField(meth, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
fieldClass = getFieldClass(meth, &staticField->field);
if (fieldClass == NULL) {
LOG_VFY("VFY: unable to recover field class from '%s'\n",
staticField->field.signature);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
if (dvmIsPrimitiveClass(fieldClass)) {
LOG_VFY("VFY: attempt to get prim field with sget-object\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
setRegisterType(workRegs, insnRegCount, decInsn.vA,
- regTypeFromClass(fieldClass), &okay);
+ regTypeFromClass(fieldClass), &failure);
}
break;
case OP_SPUT:
@@ -4514,21 +4808,29 @@
RegType srcType, fieldType;
StaticField* staticField;
- /* make sure the source register has the correct type */
srcType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
+ &failure);
+
+ /*
+ * javac generates synthetic functions that write byte values
+ * into boolean fields.
+ */
+ if (tmpType == kRegTypeBoolean && srcType == kRegTypeByte)
+ srcType = kRegTypeBoolean;
+
+ /* make sure the source register has the correct type */
if (!canConvertTo1nr(srcType, tmpType)) {
- LOG_VFY("VFY: invalid reg type %d on iput instr (need %d)\n",
+ LOG_VFY("VFY: invalid reg type %d on sput instr (need %d)\n",
srcType, tmpType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
- staticField = getStaticField(meth, decInsn.vB, &okay);
- if (!okay)
+ staticField = getStaticField(meth, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
- checkFinalFieldAccess(meth, &staticField->field, &okay);
- if (!okay)
+ checkFinalFieldAccess(meth, &staticField->field, &failure);
+ if (!VERIFY_OK(failure))
break;
/*
@@ -4543,27 +4845,27 @@
LOG_VFY("VFY: invalid sput-1nr of %s.%s (inst=%d actual=%d)\n",
staticField->field.clazz->descriptor,
staticField->field.name, tmpType, fieldType);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
break;
case OP_SPUT_WIDE:
- tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &okay);
- if (okay) {
+ tmpType = getRegisterType(workRegs, insnRegCount, decInsn.vA, &failure);
+ if (VERIFY_OK(failure)) {
RegType typeHi =
- getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &okay);
- checkTypeCategory(tmpType, kTypeCategory2, &okay);
- checkWidePair(tmpType, typeHi, &okay);
+ getRegisterType(workRegs, insnRegCount, decInsn.vA+1, &failure);
+ checkTypeCategory(tmpType, kTypeCategory2, &failure);
+ checkWidePair(tmpType, typeHi, &failure);
}
- if (okay) {
+ if (VERIFY_OK(failure)) {
StaticField* staticField;
- staticField = getStaticField(meth, decInsn.vB, &okay);
- if (!okay)
+ staticField = getStaticField(meth, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
- checkFinalFieldAccess(meth, &staticField->field, &okay);
- if (!okay)
+ checkFinalFieldAccess(meth, &staticField->field, &failure);
+ if (!VERIFY_OK(failure))
break;
/* check the type, which should be prim */
@@ -4576,7 +4878,7 @@
LOG_VFY("VFY: invalid sput-wide of %s.%s\n",
staticField->field.clazz->descriptor,
staticField->field.name);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -4588,30 +4890,30 @@
StaticField* staticField;
RegType valueType;
- staticField = getStaticField(meth, decInsn.vB, &okay);
- if (!okay)
+ staticField = getStaticField(meth, decInsn.vB, &failure);
+ if (!VERIFY_OK(failure))
break;
- checkFinalFieldAccess(meth, &staticField->field, &okay);
- if (!okay)
+ checkFinalFieldAccess(meth, &staticField->field, &failure);
+ if (!VERIFY_OK(failure))
break;
fieldClass = getFieldClass(meth, &staticField->field);
if (fieldClass == NULL) {
LOG_VFY("VFY: unable to recover field class from '%s'\n",
staticField->field.signature);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
valueType = getRegisterType(workRegs, insnRegCount, decInsn.vA,
- &okay);
- if (!okay)
+ &failure);
+ if (!VERIFY_OK(failure))
break;
if (!regTypeIsReference(valueType)) {
LOG_VFY("VFY: storing non-ref v%d into ref field '%s' (%s)\n",
decInsn.vA, staticField->field.name,
fieldClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
if (valueType != kRegTypeZero) {
@@ -4619,7 +4921,7 @@
if (valueClass == NULL) {
LOG_VFY("VFY: storing uninit ref v%d into ref field\n",
decInsn.vA);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
/* allow if field is any interface or field is base class */
@@ -4630,7 +4932,7 @@
valueClass->descriptor, fieldClass->descriptor,
staticField->field.clazz->descriptor,
staticField->field.name);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -4654,11 +4956,11 @@
calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
&decInsn, uninitMap, METHOD_VIRTUAL, isRange,
- isSuper, &okay);
- if (!okay)
+ isSuper, &failure);
+ if (!VERIFY_OK(failure))
break;
returnType = getMethodReturnType(calledMethod);
- setResultRegisterType(workRegs, insnRegCount, returnType, &okay);
+ setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
justSetResult = true;
}
break;
@@ -4672,8 +4974,8 @@
isRange = (decInsn.opCode == OP_INVOKE_DIRECT_RANGE);
calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
&decInsn, uninitMap, METHOD_DIRECT, isRange,
- false, &okay);
- if (!okay)
+ false, &failure);
+ if (!VERIFY_OK(failure))
break;
/*
@@ -4688,14 +4990,14 @@
if (isInitMethod(calledMethod)) {
RegType thisType;
thisType = getInvocationThis(workRegs, insnRegCount,
- &decInsn, &okay);
- if (!okay)
+ &decInsn, &failure);
+ if (!VERIFY_OK(failure))
break;
/* no null refs allowed (?) */
if (thisType == kRegTypeZero) {
LOG_VFY("VFY: unable to initialize null ref\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4709,20 +5011,20 @@
if (thisClass != meth->clazz) {
LOG_VFY("VFY: invoke-direct <init> on super only "
"allowed for 'this' in <init>");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
} else if (calledMethod->clazz != thisClass) {
LOG_VFY("VFY: invoke-direct <init> must be on current "
"class or super\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
/* arg must be an uninitialized reference */
if (!regTypeIsUninitReference(thisType)) {
LOG_VFY("VFY: can only initialize the uninitialized\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4734,13 +5036,13 @@
*/
int uidx = regTypeToUninitIndex(thisType);
markRefsAsInitialized(workRegs, insnRegCount, uninitMap,
- thisType, &okay);
- if (!okay)
+ thisType, &failure);
+ if (!VERIFY_OK(failure))
break;
}
returnType = getMethodReturnType(calledMethod);
setResultRegisterType(workRegs, insnRegCount,
- returnType, &okay);
+ returnType, &failure);
justSetResult = true;
}
break;
@@ -4754,12 +5056,12 @@
isRange = (decInsn.opCode == OP_INVOKE_STATIC_RANGE);
calledMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
&decInsn, uninitMap, METHOD_STATIC, isRange,
- false, &okay);
- if (!okay)
+ false, &failure);
+ if (!VERIFY_OK(failure))
break;
returnType = getMethodReturnType(calledMethod);
- setResultRegisterType(workRegs, insnRegCount, returnType, &okay);
+ setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
justSetResult = true;
}
break;
@@ -4773,8 +5075,8 @@
isRange = (decInsn.opCode == OP_INVOKE_INTERFACE_RANGE);
absMethod = verifyInvocationArgs(meth, workRegs, insnRegCount,
&decInsn, uninitMap, METHOD_INTERFACE, isRange,
- false, &okay);
- if (!okay)
+ false, &failure);
+ if (!VERIFY_OK(failure))
break;
#if 0 /* can't do this here, fails on dalvik test 052-verifier-fun */
@@ -4784,8 +5086,8 @@
* interface classes, this might have reduced to Object.
*/
thisType = getInvocationThis(workRegs, insnRegCount,
- &decInsn, &okay);
- if (!okay)
+ &decInsn, &failure);
+ if (!VERIFY_OK(failure))
break;
if (thisType == kRegTypeZero) {
@@ -4796,7 +5098,7 @@
thisClass = regTypeInitializedReferenceToClass(thisType);
if (thisClass == NULL) {
LOG_VFY("VFY: interface call on uninitialized\n");
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
@@ -4812,7 +5114,7 @@
{
LOG_VFY("VFY: unable to match absMethod '%s' with %s interfaces\n",
absMethod->name, thisClass->descriptor);
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
}
}
@@ -4824,7 +5126,7 @@
* in the abstract method, so we're good.
*/
returnType = getMethodReturnType(absMethod);
- setResultRegisterType(workRegs, insnRegCount, returnType, &okay);
+ setResultRegisterType(workRegs, insnRegCount, returnType, &failure);
justSetResult = true;
}
break;
@@ -4832,80 +5134,80 @@
case OP_NEG_INT:
case OP_NOT_INT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, &okay);
+ kRegTypeInteger, kRegTypeInteger, &failure);
break;
case OP_NEG_LONG:
case OP_NOT_LONG:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeLongLo, &okay);
+ kRegTypeLongLo, kRegTypeLongLo, &failure);
break;
case OP_NEG_FLOAT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeFloat, kRegTypeFloat, &okay);
+ kRegTypeFloat, kRegTypeFloat, &failure);
break;
case OP_NEG_DOUBLE:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeDoubleLo, kRegTypeDoubleLo, &okay);
+ kRegTypeDoubleLo, kRegTypeDoubleLo, &failure);
break;
case OP_INT_TO_LONG:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeInteger, &okay);
+ kRegTypeLongLo, kRegTypeInteger, &failure);
break;
case OP_INT_TO_FLOAT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeFloat, kRegTypeInteger, &okay);
+ kRegTypeFloat, kRegTypeInteger, &failure);
break;
case OP_INT_TO_DOUBLE:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeDoubleLo, kRegTypeInteger, &okay);
+ kRegTypeDoubleLo, kRegTypeInteger, &failure);
break;
case OP_LONG_TO_INT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeLongLo, &okay);
+ kRegTypeInteger, kRegTypeLongLo, &failure);
break;
case OP_LONG_TO_FLOAT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeFloat, kRegTypeLongLo, &okay);
+ kRegTypeFloat, kRegTypeLongLo, &failure);
break;
case OP_LONG_TO_DOUBLE:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeDoubleLo, kRegTypeLongLo, &okay);
+ kRegTypeDoubleLo, kRegTypeLongLo, &failure);
break;
case OP_FLOAT_TO_INT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeFloat, &okay);
+ kRegTypeInteger, kRegTypeFloat, &failure);
break;
case OP_FLOAT_TO_LONG:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeFloat, &okay);
+ kRegTypeLongLo, kRegTypeFloat, &failure);
break;
case OP_FLOAT_TO_DOUBLE:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeDoubleLo, kRegTypeFloat, &okay);
+ kRegTypeDoubleLo, kRegTypeFloat, &failure);
break;
case OP_DOUBLE_TO_INT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeDoubleLo, &okay);
+ kRegTypeInteger, kRegTypeDoubleLo, &failure);
break;
case OP_DOUBLE_TO_LONG:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeDoubleLo, &okay);
+ kRegTypeLongLo, kRegTypeDoubleLo, &failure);
break;
case OP_DOUBLE_TO_FLOAT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeFloat, kRegTypeDoubleLo, &okay);
+ kRegTypeFloat, kRegTypeDoubleLo, &failure);
break;
case OP_INT_TO_BYTE:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeByte, kRegTypeInteger, &okay);
+ kRegTypeByte, kRegTypeInteger, &failure);
break;
case OP_INT_TO_CHAR:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeChar, kRegTypeInteger, &okay);
+ kRegTypeChar, kRegTypeInteger, &failure);
break;
case OP_INT_TO_SHORT:
checkUnop(workRegs, insnRegCount, &decInsn,
- kRegTypeShort, kRegTypeInteger, &okay);
+ kRegTypeShort, kRegTypeInteger, &failure);
break;
case OP_ADD_INT:
@@ -4917,13 +5219,13 @@
case OP_SHR_INT:
case OP_USHR_INT:
checkBinop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &okay);
+ kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
break;
case OP_AND_INT:
case OP_OR_INT:
case OP_XOR_INT:
checkBinop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &okay);
+ kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
break;
case OP_ADD_LONG:
case OP_SUB_LONG:
@@ -4934,14 +5236,14 @@
case OP_OR_LONG:
case OP_XOR_LONG:
checkBinop(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &okay);
+ kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
break;
case OP_SHL_LONG:
case OP_SHR_LONG:
case OP_USHR_LONG:
/* shift distance is Int, making these different from other binops */
checkBinop(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &okay);
+ kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
break;
case OP_ADD_FLOAT:
case OP_SUB_FLOAT:
@@ -4949,7 +5251,7 @@
case OP_DIV_FLOAT:
case OP_REM_FLOAT:
checkBinop(workRegs, insnRegCount, &decInsn,
- kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &okay);
+ kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
break;
case OP_ADD_DOUBLE:
case OP_SUB_DOUBLE:
@@ -4957,7 +5259,8 @@
case OP_DIV_DOUBLE:
case OP_REM_DOUBLE:
checkBinop(workRegs, insnRegCount, &decInsn,
- kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false, &okay);
+ kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
+ &failure);
break;
case OP_ADD_INT_2ADDR:
case OP_SUB_INT_2ADDR:
@@ -4967,17 +5270,17 @@
case OP_SHR_INT_2ADDR:
case OP_USHR_INT_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &okay);
+ kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
break;
case OP_AND_INT_2ADDR:
case OP_OR_INT_2ADDR:
case OP_XOR_INT_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &okay);
+ kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, true, &failure);
break;
case OP_DIV_INT_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &okay);
+ kRegTypeInteger, kRegTypeInteger, kRegTypeInteger, false, &failure);
break;
case OP_ADD_LONG_2ADDR:
case OP_SUB_LONG_2ADDR:
@@ -4988,13 +5291,13 @@
case OP_OR_LONG_2ADDR:
case OP_XOR_LONG_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &okay);
+ kRegTypeLongLo, kRegTypeLongLo, kRegTypeLongLo, false, &failure);
break;
case OP_SHL_LONG_2ADDR:
case OP_SHR_LONG_2ADDR:
case OP_USHR_LONG_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &okay);
+ kRegTypeLongLo, kRegTypeLongLo, kRegTypeInteger, false, &failure);
break;
case OP_ADD_FLOAT_2ADDR:
case OP_SUB_FLOAT_2ADDR:
@@ -5002,7 +5305,7 @@
case OP_DIV_FLOAT_2ADDR:
case OP_REM_FLOAT_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &okay);
+ kRegTypeFloat, kRegTypeFloat, kRegTypeFloat, false, &failure);
break;
case OP_ADD_DOUBLE_2ADDR:
case OP_SUB_DOUBLE_2ADDR:
@@ -5010,7 +5313,8 @@
case OP_DIV_DOUBLE_2ADDR:
case OP_REM_DOUBLE_2ADDR:
checkBinop2addr(workRegs, insnRegCount, &decInsn,
- kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false, &okay);
+ kRegTypeDoubleLo, kRegTypeDoubleLo, kRegTypeDoubleLo, false,
+ &failure);
break;
case OP_ADD_INT_LIT16:
case OP_RSUB_INT:
@@ -5018,13 +5322,13 @@
case OP_DIV_INT_LIT16:
case OP_REM_INT_LIT16:
checkLitop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, false, &okay);
+ kRegTypeInteger, kRegTypeInteger, false, &failure);
break;
case OP_AND_INT_LIT16:
case OP_OR_INT_LIT16:
case OP_XOR_INT_LIT16:
checkLitop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, true, &okay);
+ kRegTypeInteger, kRegTypeInteger, true, &failure);
break;
case OP_ADD_INT_LIT8:
case OP_RSUB_INT_LIT8:
@@ -5032,18 +5336,35 @@
case OP_DIV_INT_LIT8:
case OP_REM_INT_LIT8:
case OP_SHL_INT_LIT8:
- case OP_SHR_INT_LIT8:
- case OP_USHR_INT_LIT8:
checkLitop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, false, &okay);
+ kRegTypeInteger, kRegTypeInteger, false, &failure);
+ break;
+ case OP_SHR_INT_LIT8:
+ tmpType = adjustForRightShift(workRegs, insnRegCount,
+ decInsn.vB, decInsn.vC, false, &failure);
+ checkLitop(workRegs, insnRegCount, &decInsn,
+ tmpType, kRegTypeInteger, false, &failure);
+ break;
+ case OP_USHR_INT_LIT8:
+ tmpType = adjustForRightShift(workRegs, insnRegCount,
+ decInsn.vB, decInsn.vC, true, &failure);
+ checkLitop(workRegs, insnRegCount, &decInsn,
+ tmpType, kRegTypeInteger, false, &failure);
break;
case OP_AND_INT_LIT8:
case OP_OR_INT_LIT8:
case OP_XOR_INT_LIT8:
checkLitop(workRegs, insnRegCount, &decInsn,
- kRegTypeInteger, kRegTypeInteger, true, &okay);
+ kRegTypeInteger, kRegTypeInteger, true, &failure);
break;
+ /*
+ * This falls into the general category of "optimized" instructions,
+ * which don't generally appear during verification. Because it's
+ * inserted in the course of verification, we can expect to see it here.
+ */
+ case OP_THROW_VERIFICATION_ERROR:
+ break;
/*
* Verifying "quickened" instructions is tricky, because we have
@@ -5089,7 +5410,7 @@
case OP_INVOKE_VIRTUAL_QUICK_RANGE:
case OP_INVOKE_SUPER_QUICK:
case OP_INVOKE_SUPER_QUICK_RANGE:
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
/* these should never appear */
@@ -5112,14 +5433,13 @@
case OP_UNUSED_EA:
case OP_UNUSED_EB:
case OP_UNUSED_EC:
- case OP_UNUSED_ED:
case OP_UNUSED_EF:
case OP_UNUSED_F1:
case OP_UNUSED_FC:
case OP_UNUSED_FD:
case OP_UNUSED_FE:
case OP_UNUSED_FF:
- okay = false;
+ failure = VERIFY_ERROR_GENERIC;
break;
/*
@@ -5128,10 +5448,28 @@
*/
}
- if (!okay) {
- LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
- decInsn.opCode, insnIdx);
- goto bail;
+ if (!VERIFY_OK(failure)) {
+ if (failure == VERIFY_ERROR_GENERIC || gDvm.optimizing) {
+ /* immediate failure, reject class */
+ LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
+ decInsn.opCode, insnIdx);
+ goto bail;
+ } else {
+ /* replace opcode and continue on */
+ LOGD("VFY: replacing opcode 0x%02x at 0x%04x\n",
+ decInsn.opCode, insnIdx);
+ if (!replaceFailingInstruction(meth, insnFlags, insnIdx, failure)) {
+ LOG_VFY_METH(meth, "VFY: rejecting opcode 0x%02x at 0x%04x\n",
+ decInsn.opCode, insnIdx);
+ goto bail;
+ }
+ /* IMPORTANT: meth->insns may have been changed */
+ insns = meth->insns + insnIdx;
+
+ /* continue on as if we just handled a throw-verification-error */
+ failure = VERIFY_ERROR_NONE;
+ nextFlags = kInstrCanThrow;
+ }
}
/*
@@ -5206,6 +5544,7 @@
if (!checkMoveException(meth, insnIdx+branchTarget, "branch"))
goto bail;
+ /* update branch target, set "changed" if appropriate */
updateRegisters(meth, insnFlags, regTable, insnIdx+branchTarget,
workRegs);
}
@@ -5297,6 +5636,7 @@
return result;
}
+
/*
* callback function used in dumpRegTypes to print local vars
* valid at a given address.
diff --git a/vm/analysis/CodeVerify.h b/vm/analysis/CodeVerify.h
index 0cd4638..1b93655 100644
--- a/vm/analysis/CodeVerify.h
+++ b/vm/analysis/CodeVerify.h
@@ -198,10 +198,10 @@
return (insnFlags[addr] & kInsnFlagGcPoint) != 0;
}
INLINE void dvmInsnSetGcPoint(InsnFlags* insnFlags, int addr,
- bool isBranch)
+ bool isGcPoint)
{
- assert(isBranch);
- //if (isBranch)
+ assert(isGcPoint);
+ //if (isGcPoint)
insnFlags[addr] |= kInsnFlagGcPoint;
//else
// insnFlags[addr] &= ~kInsnFlagGcPoint;
@@ -259,7 +259,7 @@
* Verify bytecode in "meth". "insnFlags" should be populated with
* instruction widths and "in try" flags.
*/
-bool dvmVerifyCodeFlow(const Method* meth, InsnFlags* insnFlags,
+bool dvmVerifyCodeFlow(Method* meth, InsnFlags* insnFlags,
UninitInstanceMap* uninitMap);
#endif /*_DALVIK_CODEVERIFY*/
diff --git a/vm/analysis/DexOptimize.c b/vm/analysis/DexOptimize.c
index d086b99..025e7cb 100644
--- a/vm/analysis/DexOptimize.c
+++ b/vm/analysis/DexOptimize.c
@@ -25,6 +25,7 @@
#include "Dalvik.h"
#include "libdex/InstrUtils.h"
#include "libdex/OptInvocation.h"
+#include "analysis/RegisterMap.h"
#include <zlib.h>
@@ -50,7 +51,7 @@
/* fwd */
static int writeDependencies(int fd, u4 modWhen, u4 crc);
static bool writeAuxData(int fd, const DexClassLookup* pClassLookup,\
- const IndexMapSet* pIndexMapSet);
+ const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
static void logFailedWrite(size_t expected, ssize_t actual, const char* msg,
int err);
@@ -365,6 +366,9 @@
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) {
@@ -506,6 +510,7 @@
{
DexClassLookup* pClassLookup = NULL;
IndexMapSet* pIndexMapSet = NULL;
+ RegisterMapBuilder* pRegMapBuilder = NULL;
bool doVerify, doOpt;
u4 headerFlags = 0;
@@ -566,6 +571,13 @@
* 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);
@@ -576,6 +588,7 @@
if (dvmDexFileOpenPartial(dexAddr, dexLength, &pDvmDex) != 0) {
LOGE("Unable to create DexFile\n");
+ success = false;
} else {
/*
* If configured to do so, scan the instructions, looking
@@ -586,8 +599,20 @@
*/
pIndexMapSet = dvmRewriteConstants(pDvmDex);
- updateChecksum(dexAddr, dexLength,
- (DexHeader*) pDvmDex->pHeader);
+ /*
+ * 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);
}
@@ -640,8 +665,7 @@
goto bail;
}
-
- /* compute deps length, and adjust aux start for 64-bit alignment */
+ /* compute deps length, then adjust aux start for 64-bit alignment */
auxOffset = lseek(fd, 0, SEEK_END);
depsLength = auxOffset - depsOffset;
@@ -656,7 +680,7 @@
/*
* Append any auxillary pre-computed data structures.
*/
- if (!writeAuxData(fd, pClassLookup, pIndexMapSet)) {
+ if (!writeAuxData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
LOGW("Failed writing aux data\n");
goto bail;
}
@@ -692,8 +716,11 @@
LOGV("Successfully wrote DEX header\n");
result = true;
+ //dvmRegisterMapDumpStats();
+
bail:
dvmFreeIndexMapSet(pIndexMapSet);
+ dvmFreeRegisterMapBuilder(pRegMapBuilder);
free(pClassLookup);
return result;
}
@@ -888,7 +915,8 @@
}
val = read4LE(&ptr);
if (val != DALVIK_VM_BUILD) {
- LOGI("DexOpt: VM build mismatch (%d vs %d)\n", val, DALVIK_VM_BUILD);
+ LOGD("DexOpt: VM build version mismatch (%d vs %d)\n",
+ val, DALVIK_VM_BUILD);
goto bail;
}
@@ -1085,19 +1113,28 @@
* 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 IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
{
/* pre-computed class lookup hash table */
- if (!writeChunk(fd, (u4) kDexChunkClassLookup, pClassLookup,
- pClassLookup->size))
+ 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))
+ 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;
}
@@ -1622,8 +1659,11 @@
* 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)
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+ VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
ClassObject* resClass;
@@ -1645,6 +1685,23 @@
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;
}
@@ -1659,6 +1716,8 @@
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;
}
@@ -1669,6 +1728,8 @@
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;
}
@@ -1677,8 +1738,11 @@
/*
* Alternate version of dvmResolveInstField().
+ *
+ * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
*/
-InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx)
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+ VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
InstField* resField;
@@ -1693,10 +1757,11 @@
/*
* Find the field's class.
*/
- resClass = dvmOptResolveClass(referrer, pFieldId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
if (resClass == NULL) {
//dvmClearOptException(dvmThreadSelf());
assert(!dvmCheckException(dvmThreadSelf()));
+ if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
return NULL;
}
@@ -1707,6 +1772,8 @@
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;
}
@@ -1724,6 +1791,8 @@
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;
}
@@ -1734,8 +1803,11 @@
* 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)
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+ VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
StaticField* resField;
@@ -1750,10 +1822,11 @@
/*
* Find the field's class.
*/
- resClass = dvmOptResolveClass(referrer, pFieldId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
if (resClass == NULL) {
//dvmClearOptException(dvmThreadSelf());
assert(!dvmCheckException(dvmThreadSelf()));
+ if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
return NULL;
}
@@ -1762,6 +1835,8 @@
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;
}
@@ -1784,6 +1859,8 @@
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;
}
@@ -1809,7 +1886,7 @@
InstField* field;
int byteOffset;
- field = dvmOptResolveInstField(clazz, fieldIdx);
+ 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,
@@ -1833,9 +1910,11 @@
* 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)
+ MethodType methodType, VerifyError* pFailure)
{
DvmDex* pDvmDex = referrer->pDvmDex;
Method* resMethod;
@@ -1852,16 +1931,22 @@
pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
- resClass = dvmOptResolveClass(referrer, pMethodId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, pFailure);
if (resClass == NULL) {
- /* can't find the class that the method is a part of */
+ /*
+ * 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;
}
@@ -1887,6 +1972,8 @@
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;
}
@@ -1895,6 +1982,8 @@
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;
}
@@ -1925,6 +2014,8 @@
referrer->descriptor);
free(desc);
}
+ if (pFailure != NULL)
+ *pFailure = VERIFY_ERROR_ACCESS_METHOD;
return NULL;
}
@@ -1945,7 +2036,7 @@
Method* baseMethod;
u2 methodIdx = insns[1];
- baseMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_VIRTUAL);
+ 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,
@@ -1989,7 +2080,7 @@
Method* calledMethod;
u2 methodIdx = insns[1];
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, METHOD_DIRECT);
+ 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,
@@ -2021,6 +2112,8 @@
/*
* 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)
@@ -2039,7 +2132,7 @@
pMethodId = dexGetMethodId(pDvmDex->pDexFile, methodIdx);
- resClass = dvmOptResolveClass(referrer, pMethodId->classIdx);
+ resClass = dvmOptResolveClass(referrer, pMethodId->classIdx, NULL);
if (resClass == NULL) {
/* can't find the class that the method is a part of */
dvmClearOptException(dvmThreadSelf());
@@ -2115,7 +2208,7 @@
//return false;
- calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType);
+ calledMethod = dvmOptResolveMethod(clazz, methodIdx, methodType, NULL);
if (calledMethod == NULL) {
LOGV("+++ DexOpt inline: can't find %d\n", methodIdx);
return false;
diff --git a/vm/analysis/DexOptimize.h b/vm/analysis/DexOptimize.h
index 01aa828..8ae2af5 100644
--- a/vm/analysis/DexOptimize.h
+++ b/vm/analysis/DexOptimize.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* DEX optimization declarations.
*/
@@ -36,6 +37,25 @@
};
/*
+ * An enumeration of problems that can turn up during verification.
+ */
+typedef enum VerifyError {
+ VERIFY_ERROR_NONE = 0, /* no error; must be zero */
+ VERIFY_ERROR_GENERIC, /* VerifyError */
+
+ VERIFY_ERROR_NO_CLASS, /* NoClassDefFoundError (ref=class) */
+ VERIFY_ERROR_NO_FIELD, /* NoSuchFieldError (ref=field) */
+ VERIFY_ERROR_NO_METHOD, /* NoSuchMethodError (ref=method) */
+ VERIFY_ERROR_ACCESS_CLASS, /* IllegalAccessError (ref=class) */
+ VERIFY_ERROR_ACCESS_FIELD, /* IllegalAccessError (ref=field) */
+ VERIFY_ERROR_ACCESS_METHOD, /* IllegalAccessError (ref=method) */
+ VERIFY_ERROR_CLASS_CHANGE, /* IncompatibleClassChangeError (ref=class) */
+ VERIFY_ERROR_INSTANTIATION, /* InstantiationError (ref=class) */
+} VerifyError;
+
+#define VERIFY_OK(_failure) ((_failure) == VERIFY_ERROR_NONE)
+
+/*
* Given the full path to a DEX or Jar file, and (if appropriate) the name
* within the Jar, open the optimized version from the cache.
*
@@ -81,11 +101,14 @@
* Abbreviated resolution functions, for use by optimization and verification
* code.
*/
-ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx);
+ClassObject* dvmOptResolveClass(ClassObject* referrer, u4 classIdx,
+ VerifyError* pFailure);
Method* dvmOptResolveMethod(ClassObject* referrer, u4 methodIdx,
- MethodType methodType);
+ MethodType methodType, VerifyError* pFailure);
Method* dvmOptResolveInterfaceMethod(ClassObject* referrer, u4 methodIdx);
-InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx);
-StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx);
+InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
+ VerifyError* pFailure);
+StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
+ VerifyError* pFailure);
#endif /*_DALVIK_DEXOPTIMIZE*/
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index 354d68f..10251db 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -36,11 +36,18 @@
gDvm.instrWidth = dexCreateInstrWidthTable();
gDvm.instrFormat = dexCreateInstrFormatTable();
gDvm.instrFlags = dexCreateInstrFlagsTable();
- return (gDvm.instrWidth != NULL && gDvm.instrFormat!= NULL);
+ if (gDvm.instrWidth == NULL || gDvm.instrFormat == NULL ||
+ gDvm.instrFlags == NULL)
+ {
+ LOGE("Unable to create instruction tables\n");
+ return false;
+ }
+
+ return true;
}
/*
- * Initialize some things we need for verification.
+ * Free up some things we needed for verification.
*/
void dvmVerificationShutdown(void)
{
@@ -533,15 +540,36 @@
dvmInsnSetBranchTarget(insnFlags, 0, true);
for (i = 0; i < insnCount; /**/) {
- static int gcMask = kInstrCanBranch | kInstrCanSwitch |
+ /*
+ * These types of instructions can be GC points. To support precise
+ * GC, all such instructions must export the PC in the interpreter,
+ * or the GC won't be able to identify the current PC for the thread.
+ */
+ static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
kInstrCanThrow | kInstrCanReturn;
+
int width = dvmInsnGetWidth(insnFlags, i);
OpCode opcode = *insns & 0xff;
InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
int offset, absOffset;
- if ((opFlags & gcMask) != 0)
- dvmInsnSetGcPoint(insnFlags, i, true);
+ if ((opFlags & gcMask) != 0) {
+ /*
+ * This instruction is probably a GC point. Branch instructions
+ * only qualify if they go backward, so we need to check the
+ * offset.
+ */
+ int offset = -1;
+ bool unused;
+ if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
+ if (offset < 0) {
+ dvmInsnSetGcPoint(insnFlags, i, true);
+ }
+ } else {
+ /* not a branch target */
+ dvmInsnSetGcPoint(insnFlags, i, true);
+ }
+ }
switch (opcode) {
case OP_NOP:
diff --git a/vm/analysis/RegisterMap.c b/vm/analysis/RegisterMap.c
index b02874a..20272f2 100644
--- a/vm/analysis/RegisterMap.c
+++ b/vm/analysis/RegisterMap.c
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-// ** UNDER CONSTRUCTION **
-
/*
* This code generate "register maps" for Dalvik bytecode. In a stack-based
* VM we might call these "stack maps". They are used to increase the
@@ -27,9 +25,1828 @@
#include "analysis/RegisterMap.h"
#include "libdex/DexCatch.h"
#include "libdex/InstrUtils.h"
+#include "libdex/Leb128.h"
#include <stddef.h>
+/* double-check the compression */
+#define REGISTER_MAP_VERIFY true
+
+/* verbose logging */
+#define REGISTER_MAP_VERBOSE false
+
+
+// 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);
+
+static void computeMapStats(RegisterMap* pMap, const Method* method);
+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.
+ */
+#define kMaxGcPointGap 50
+#define kUpdatePosnMinRegs 24
+#define kNumUpdatePosns 8
+#define kMaxDiffBits 20
+typedef struct MapStats {
+ /*
+ * Buckets measuring the distance between GC points. This tells us how
+ * many bits we need to encode the advancing program counter. We ignore
+ * some of the "long tail" entries.
+ */
+ int gcPointGap[kMaxGcPointGap];
+
+ /*
+ * Number of gaps. Equal to (number of gcPoints - number of methods),
+ * since the computation isn't including the initial gap.
+ */
+ int gcGapCount;
+
+ /*
+ * Number of gaps.
+ */
+ int totalGcPointCount;
+
+ /*
+ * For larger methods (>= 24 registers), measure in which octant register
+ * updates occur. This should help us understand whether register
+ * changes tend to cluster in the low regs even for large methods.
+ */
+ int updatePosn[kNumUpdatePosns];
+
+ /*
+ * For all methods, count up the number of changes to registers < 16
+ * and >= 16.
+ */
+ int updateLT16;
+ int updateGE16;
+
+ /*
+ * Histogram of the number of bits that differ between adjacent entries.
+ */
+ int numDiffBits[kMaxDiffBits];
+
+
+ /*
+ * Track the number of expanded maps, and the heap space required to
+ * hold them.
+ */
+ int numExpandedMaps;
+ int totalExpandedMapSize;
+} MapStats;
+#endif
+
+/*
+ * Prepare some things.
+ */
+bool dvmRegisterMapStartup(void)
+{
+#ifdef REGISTER_MAP_STATS
+ MapStats* pStats = calloc(1, sizeof(MapStats));
+ gDvm.registerMapStats = pStats;
+#endif
+ return true;
+}
+
+/*
+ * Clean up.
+ */
+void dvmRegisterMapShutdown(void)
+{
+#ifdef REGISTER_MAP_STATS
+ free(gDvm.registerMapStats);
+#endif
+}
+
+/*
+ * Write stats to log file.
+ */
+void dvmRegisterMapDumpStats(void)
+{
+#ifdef REGISTER_MAP_STATS
+ MapStats* pStats = (MapStats*) gDvm.registerMapStats;
+ int i, end;
+
+ for (end = kMaxGcPointGap-1; end >= 0; end--) {
+ if (pStats->gcPointGap[end] != 0)
+ break;
+ }
+
+ LOGI("Register Map gcPointGap stats (diff count=%d, total=%d):\n",
+ pStats->gcGapCount, pStats->totalGcPointCount);
+ assert(pStats->gcPointGap[0] == 0);
+ for (i = 1; i <= end; i++) {
+ LOGI(" %2d %d\n", i, pStats->gcPointGap[i]);
+ }
+
+
+ for (end = kMaxDiffBits-1; end >= 0; end--) {
+ if (pStats->numDiffBits[end] != 0)
+ break;
+ }
+
+ LOGI("Register Map bit difference stats:\n");
+ for (i = 0; i <= end; i++) {
+ LOGI(" %2d %d\n", i, pStats->numDiffBits[i]);
+ }
+
+
+ LOGI("Register Map update position stats (lt16=%d ge16=%d):\n",
+ pStats->updateLT16, pStats->updateGE16);
+ for (i = 0; i < kNumUpdatePosns; i++) {
+ LOGI(" %2d %d\n", i, pStats->updatePosn[i]);
+ }
+#endif
+}
+
+
+/*
+ * ===========================================================================
+ * Map generation
+ * ===========================================================================
+ */
+
+/*
+ * Generate the register map for a method that has just been verified
+ * (i.e. we're doing this as part of verification).
+ *
+ * For type-precise determination we have all the data we need, so we
+ * just need to encode it in some clever fashion.
+ *
+ * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
+ */
+RegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata)
+{
+ static const int kHeaderSize = offsetof(RegisterMap, data);
+ RegisterMap* pMap = NULL;
+ RegisterMap* pResult = NULL;
+ RegisterMapFormat format;
+ u1 regWidth;
+ u1* mapData;
+ int i, bytesForAddr, gcPointCount;
+ int bufSize;
+
+ if (vdata->method->registersSize >= 2048) {
+ LOGE("ERROR: register map can't handle %d registers\n",
+ vdata->method->registersSize);
+ goto bail;
+ }
+ regWidth = (vdata->method->registersSize + 7) / 8;
+
+ /*
+ * Decide if we need 8 or 16 bits to hold the address. Strictly speaking
+ * we only need 16 bits if we actually encode an address >= 256 -- if
+ * the method has a section at the end without GC points (e.g. array
+ * data) we don't need to count it. The situation is unusual, and
+ * detecting it requires scanning the entire method, so we don't bother.
+ */
+ if (vdata->insnsSize < 256) {
+ format = kRegMapFormatCompact8;
+ bytesForAddr = 1;
+ } else {
+ format = kRegMapFormatCompact16;
+ bytesForAddr = 2;
+ }
+
+ /*
+ * Count up the number of GC point instructions.
+ *
+ * NOTE: this does not automatically include the first instruction,
+ * since we don't count method entry as a GC point.
+ */
+ gcPointCount = 0;
+ for (i = 0; i < vdata->insnsSize; i++) {
+ if (dvmInsnIsGcPoint(vdata->insnFlags, i))
+ gcPointCount++;
+ }
+ if (gcPointCount >= 65536) {
+ /* we could handle this, but in practice we don't get near this */
+ LOGE("ERROR: register map can't handle %d gc points in one method\n",
+ gcPointCount);
+ goto bail;
+ }
+
+ /*
+ * Allocate a buffer to hold the map data.
+ */
+ bufSize = kHeaderSize + gcPointCount * (bytesForAddr + regWidth);
+
+ LOGV("+++ grm: %s.%s (adr=%d gpc=%d rwd=%d bsz=%d)\n",
+ vdata->method->clazz->descriptor, vdata->method->name,
+ bytesForAddr, gcPointCount, regWidth, bufSize);
+
+ pMap = (RegisterMap*) malloc(bufSize);
+ dvmRegisterMapSetFormat(pMap, format);
+ dvmRegisterMapSetOnHeap(pMap, true);
+ dvmRegisterMapSetRegWidth(pMap, regWidth);
+ dvmRegisterMapSetNumEntries(pMap, gcPointCount);
+
+ /*
+ * Populate it.
+ */
+ mapData = pMap->data;
+ for (i = 0; i < vdata->insnsSize; i++) {
+ if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
+ assert(vdata->addrRegs[i] != NULL);
+ if (format == kRegMapFormatCompact8) {
+ *mapData++ = i;
+ } else /*kRegMapFormatCompact16*/ {
+ *mapData++ = i & 0xff;
+ *mapData++ = i >> 8;
+ }
+ outputTypeVector(vdata->addrRegs[i], vdata->insnRegCount, mapData);
+ mapData += regWidth;
+ }
+ }
+
+ LOGV("mapData=%p pMap=%p bufSize=%d\n", mapData, pMap, bufSize);
+ assert(mapData - (const u1*) pMap == bufSize);
+
+#if 1
+ if (!verifyMap(vdata, pMap))
+ goto bail;
+#endif
+#ifdef REGISTER_MAP_STATS
+ computeMapStats(pMap, vdata->method);
+#endif
+
+ /*
+ * Try to compress the map.
+ */
+ RegisterMap* pCompMap;
+
+ pCompMap = compressMapDifferential(pMap, vdata->method);
+ if (pCompMap != NULL) {
+ if (REGISTER_MAP_VERIFY) {
+ /*
+ * Expand the compressed map we just created, and compare it
+ * to the original. Abort the VM if it doesn't match up.
+ */
+ RegisterMap* pUncompMap;
+ pUncompMap = uncompressMapDifferential(pCompMap);
+ if (pUncompMap == NULL) {
+ LOGE("Map failed to uncompress - %s.%s\n",
+ vdata->method->clazz->descriptor,
+ vdata->method->name);
+ free(pCompMap);
+ /* bad - compression is broken or we're out of memory */
+ dvmAbort();
+ } else {
+ if (compareMaps(pMap, pUncompMap) != 0) {
+ LOGE("Map comparison failed - %s.%s\n",
+ vdata->method->clazz->descriptor,
+ vdata->method->name);
+ free(pCompMap);
+ /* bad - compression is broken */
+ dvmAbort();
+ }
+
+ /* verify succeeded */
+ free(pUncompMap);
+ }
+ }
+
+ if (REGISTER_MAP_VERBOSE) {
+ LOGD("Good compress on %s.%s\n",
+ vdata->method->clazz->descriptor,
+ vdata->method->name);
+ }
+ free(pMap);
+ pMap = pCompMap;
+ } else {
+ if (REGISTER_MAP_VERBOSE) {
+ LOGD("Unable to compress %s.%s (ent=%d rw=%d)\n",
+ vdata->method->clazz->descriptor,
+ vdata->method->name,
+ dvmRegisterMapGetNumEntries(pMap),
+ dvmRegisterMapGetRegWidth(pMap));
+ }
+ }
+
+ pResult = pMap;
+
+bail:
+ return pResult;
+}
+
+/*
+ * Release the storage held by a RegisterMap.
+ */
+void dvmFreeRegisterMap(RegisterMap* pMap)
+{
+ if (pMap == NULL)
+ return;
+
+ assert(dvmRegisterMapGetOnHeap(pMap));
+ free(pMap);
+}
+
+/*
+ * Determine if the RegType value is a reference type.
+ *
+ * Ordinarily we include kRegTypeZero in the "is it a reference"
+ * check. There's no value in doing so here, because we know
+ * the register can't hold anything but zero.
+ */
+static inline bool isReferenceType(RegType type)
+{
+ return (type > kRegTypeMAX || type == kRegTypeUninit);
+}
+
+/*
+ * Given a line of registers, output a bit vector that indicates whether
+ * or not the register holds a reference type (which could be null).
+ *
+ * We use '1' to indicate it's a reference, '0' for anything else (numeric
+ * value, uninitialized data, merge conflict). Register 0 will be found
+ * in the low bit of the first byte.
+ */
+static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data)
+{
+ u1 val = 0;
+ int i;
+
+ for (i = 0; i < insnRegCount; i++) {
+ RegType type = *regs++;
+ val >>= 1;
+ if (isReferenceType(type))
+ val |= 0x80; /* set hi bit */
+
+ if ((i & 0x07) == 7)
+ *data++ = val;
+ }
+ if ((i & 0x07) != 0) {
+ /* flush bits from last byte */
+ val >>= 8 - (i & 0x07);
+ *data++ = val;
+ }
+}
+
+/*
+ * Print the map as a series of binary strings.
+ *
+ * Pass in method->registersSize if known, or -1 if not.
+ */
+static void dumpRegisterMap(const RegisterMap* pMap, int registersSize)
+{
+ const u1* rawMap = pMap->data;
+ const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
+ const int numEntries = dvmRegisterMapGetNumEntries(pMap);
+ const int regWidth = dvmRegisterMapGetRegWidth(pMap);
+ int addrWidth;
+
+ switch (format) {
+ case kRegMapFormatCompact8:
+ addrWidth = 1;
+ break;
+ case kRegMapFormatCompact16:
+ addrWidth = 2;
+ break;
+ default:
+ /* can't happen */
+ LOGE("Can only dump Compact8 / Compact16 maps (not %d)\n", format);
+ return;
+ }
+
+ if (registersSize < 0)
+ registersSize = 8 * regWidth;
+ assert(registersSize <= regWidth * 8);
+
+ int ent;
+ for (ent = 0; ent < numEntries; ent++) {
+ int i, addr;
+
+ addr = *rawMap++;
+ if (addrWidth > 1)
+ addr |= (*rawMap++) << 8;
+
+ const u1* dataStart = rawMap;
+ u1 val = 0;
+
+ /* create binary string */
+ char outBuf[registersSize +1];
+ for (i = 0; i < registersSize; i++) {
+ val >>= 1;
+ if ((i & 0x07) == 0)
+ val = *rawMap++;
+
+ outBuf[i] = '0' + (val & 0x01);
+ }
+ outBuf[i] = '\0';
+
+ /* back up and create hex dump */
+ char hexBuf[regWidth * 3 +1];
+ char* cp = hexBuf;
+ rawMap = dataStart;
+ for (i = 0; i < regWidth; i++) {
+ sprintf(cp, " %02x", *rawMap++);
+ cp += 3;
+ }
+ hexBuf[i * 3] = '\0';
+
+ LOGD(" %04x %s %s\n", addr, outBuf, hexBuf);
+ }
+}
+
+/*
+ * Double-check the map.
+ *
+ * We run through all of the data in the map, and compare it to the original.
+ * Only works on uncompressed data.
+ */
+static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap)
+{
+ const u1* rawMap = pMap->data;
+ const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
+ const int numEntries = dvmRegisterMapGetNumEntries(pMap);
+ int ent;
+ bool dumpMap = false;
+
+ 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)
+ {
+ char* desc;
+ desc = dexProtoCopyMethodDescriptor(&vdata->method->prototype);
+ LOGI("Map for %s.%s %s\n", vdata->method->clazz->descriptor,
+ vdata->method->name, desc);
+ free(desc);
+
+ dumpMap = true;
+ }
+ }
+
+ if ((vdata->method->registersSize + 7) / 8 != pMap->regWidth) {
+ LOGE("GLITCH: registersSize=%d, regWidth=%d\n",
+ vdata->method->registersSize, pMap->regWidth);
+ return false;
+ }
+
+ for (ent = 0; ent < numEntries; ent++) {
+ int addr;
+
+ switch (format) {
+ case kRegMapFormatCompact8:
+ addr = *rawMap++;
+ break;
+ case kRegMapFormatCompact16:
+ addr = *rawMap++;
+ addr |= (*rawMap++) << 8;
+ break;
+ default:
+ /* shouldn't happen */
+ LOGE("GLITCH: bad format (%d)", format);
+ dvmAbort();
+ }
+
+ const u1* dataStart = rawMap;
+ const RegType* regs = vdata->addrRegs[addr];
+ if (regs == NULL) {
+ LOGE("GLITCH: addr %d has no data\n", addr);
+ return false;
+ }
+
+ u1 val = 0;
+ int i;
+
+ for (i = 0; i < vdata->method->registersSize; i++) {
+ bool bitIsRef, regIsRef;
+
+ val >>= 1;
+ if ((i & 0x07) == 0) {
+ /* load next byte of data */
+ val = *rawMap++;
+ }
+
+ bitIsRef = val & 0x01;
+
+ RegType type = regs[i];
+ regIsRef = isReferenceType(type);
+
+ if (bitIsRef != regIsRef) {
+ LOGE("GLITCH: addr %d reg %d: bit=%d reg=%d(%d)\n",
+ addr, i, bitIsRef, regIsRef, type);
+ return false;
+ }
+ }
+
+ /* rawMap now points to the address field of the next entry */
+ }
+
+ if (dumpMap)
+ dumpRegisterMap(pMap, vdata->method->registersSize);
+
+ return true;
+}
+
+
+/*
+ * ===========================================================================
+ * DEX generation & parsing
+ * ===========================================================================
+ */
+
+/*
+ * Advance "ptr" to ensure 32-bit alignment.
+ */
+static inline u1* align32(u1* ptr)
+{
+ return (u1*) (((int) ptr + 3) & ~0x03);
+}
+
+/*
+ * Compute the size, in bytes, of a register map.
+ */
+static size_t computeRegisterMapSize(const RegisterMap* pMap)
+{
+ static const int kHeaderSize = offsetof(RegisterMap, data);
+ u1 format = dvmRegisterMapGetFormat(pMap);
+ u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
+
+ assert(pMap != NULL);
+
+ switch (format) {
+ case kRegMapFormatNone:
+ return 1;
+ case kRegMapFormatCompact8:
+ return kHeaderSize + (1 + pMap->regWidth) * numEntries;
+ case kRegMapFormatCompact16:
+ return kHeaderSize + (2 + pMap->regWidth) * numEntries;
+ case kRegMapFormatDifferential:
+ {
+ /* kHeaderSize + decoded ULEB128 length */
+ const u1* ptr = pMap->data;
+ int len = readUnsignedLeb128(&ptr);
+ return len + (ptr - (u1*) pMap);
+ }
+ default:
+ LOGE("Bad register map format %d\n", format);
+ dvmAbort();
+ return 0;
+ }
+}
+
+/*
+ * Output the map for a single method, if it has one.
+ *
+ * Abstract and native methods have no map. All others are expected to
+ * have one, since we know the class verified successfully.
+ *
+ * This strips the "allocated on heap" flag from the format byte, so that
+ * direct-mapped maps are correctly identified as such.
+ */
+static bool writeMapForMethod(const Method* meth, u1** pPtr)
+{
+ if (meth->registerMap == NULL) {
+ if (!dvmIsAbstractMethod(meth) && !dvmIsNativeMethod(meth)) {
+ LOGW("Warning: no map available for %s.%s\n",
+ meth->clazz->descriptor, meth->name);
+ /* weird, but keep going */
+ }
+ *(*pPtr)++ = kRegMapFormatNone;
+ return true;
+ }
+
+ /* serialize map into the buffer */
+ size_t mapSize = computeRegisterMapSize(meth->registerMap);
+ memcpy(*pPtr, meth->registerMap, mapSize);
+
+ /* strip the "on heap" flag out of the format byte, which is always first */
+ assert(**pPtr == meth->registerMap->format);
+ **pPtr &= ~(kRegMapFormatOnHeap);
+
+ *pPtr += mapSize;
+
+ return true;
+}
+
+/*
+ * Write maps for all methods in the specified class to the buffer, which
+ * can hold at most "length" bytes. "*pPtr" will be advanced past the end
+ * of the data we write.
+ */
+static bool writeMapsAllMethods(DvmDex* pDvmDex, const ClassObject* clazz,
+ u1** pPtr, size_t length)
+{
+ RegisterMapMethodPool* pMethodPool;
+ u1* ptr = *pPtr;
+ int i, methodCount;
+
+ /* artificial limit */
+ if (clazz->virtualMethodCount + clazz->directMethodCount >= 65536) {
+ LOGE("Too many methods in %s\n", clazz->descriptor);
+ return false;
+ }
+
+ pMethodPool = (RegisterMapMethodPool*) ptr;
+ ptr += offsetof(RegisterMapMethodPool, methodData);
+ methodCount = 0;
+
+ /*
+ * Run through all methods, direct then virtual. The class loader will
+ * traverse them in the same order. (We could split them into two
+ * distinct pieces, but there doesn't appear to be any value in doing
+ * so other than that it makes class loading slightly less fragile.)
+ *
+ * The class loader won't know about miranda methods at the point
+ * where it parses this, so we omit those.
+ *
+ * TODO: consider omitting all native/abstract definitions. Should be
+ * safe, though we lose the ability to sanity-check against the
+ * method counts in the DEX file.
+ */
+ for (i = 0; i < clazz->directMethodCount; i++) {
+ const Method* meth = &clazz->directMethods[i];
+ if (dvmIsMirandaMethod(meth))
+ continue;
+ if (!writeMapForMethod(&clazz->directMethods[i], &ptr)) {
+ return false;
+ }
+ methodCount++;
+ //ptr = align32(ptr);
+ }
+
+ for (i = 0; i < clazz->virtualMethodCount; i++) {
+ const Method* meth = &clazz->virtualMethods[i];
+ if (dvmIsMirandaMethod(meth))
+ continue;
+ if (!writeMapForMethod(&clazz->virtualMethods[i], &ptr)) {
+ return false;
+ }
+ methodCount++;
+ //ptr = align32(ptr);
+ }
+
+ pMethodPool->methodCount = methodCount;
+
+ *pPtr = ptr;
+ return true;
+}
+
+/*
+ * Write maps for all classes to the specified buffer, which can hold at
+ * most "length" bytes.
+ *
+ * Returns the actual length used, or 0 on failure.
+ */
+static size_t writeMapsAllClasses(DvmDex* pDvmDex, u1* basePtr, size_t length)
+{
+ DexFile* pDexFile = pDvmDex->pDexFile;
+ u4 count = pDexFile->pHeader->classDefsSize;
+ RegisterMapClassPool* pClassPool;
+ u4* offsetTable;
+ u1* ptr = basePtr;
+ u4 idx;
+
+ assert(gDvm.optimizing);
+
+ pClassPool = (RegisterMapClassPool*) ptr;
+ ptr += offsetof(RegisterMapClassPool, classDataOffset);
+ offsetTable = (u4*) ptr;
+ ptr += count * sizeof(u4);
+
+ pClassPool->numClasses = count;
+
+ /*
+ * We want an entry for every class, loaded or not.
+ */
+ 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 have been loaded into the bootstrap class loader.
+ * If we can find it, and it was successfully pre-verified, we
+ * run through its methods and add the register maps.
+ *
+ * If it wasn't pre-verified then we know it can't have any
+ * register maps. Classes that can't be loaded or failed
+ * verification get an empty slot in the index.
+ */
+ clazz = NULL;
+ if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) != 0)
+ clazz = dvmLookupClass(classDescriptor, NULL, false);
+
+ if (clazz != NULL) {
+ offsetTable[idx] = ptr - basePtr;
+ LOGVV("%d -> offset %d (%p-%p)\n",
+ idx, offsetTable[idx], ptr, basePtr);
+
+ if (!writeMapsAllMethods(pDvmDex, clazz, &ptr,
+ length - (ptr - basePtr)))
+ {
+ return 0;
+ }
+
+ ptr = align32(ptr);
+ LOGVV("Size %s (%d+%d methods): %d\n", clazz->descriptor,
+ clazz->directMethodCount, clazz->virtualMethodCount,
+ (ptr - basePtr) - offsetTable[idx]);
+ } else {
+ LOGV("%4d NOT mapadding '%s'\n", idx, classDescriptor);
+ assert(offsetTable[idx] == 0);
+ }
+ }
+
+ if (ptr - basePtr >= (int)length) {
+ /* a bit late */
+ LOGE("Buffer overrun\n");
+ dvmAbort();
+ }
+
+ return ptr - basePtr;
+}
+
+/*
+ * Generate a register map set for all verified classes in "pDvmDex".
+ */
+RegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex)
+{
+ RegisterMapBuilder* pBuilder;
+
+ pBuilder = (RegisterMapBuilder*) calloc(1, sizeof(RegisterMapBuilder));
+ if (pBuilder == NULL)
+ return NULL;
+
+ /*
+ * We have a couple of options here:
+ * (1) Compute the size of the output, and malloc a buffer.
+ * (2) Create a "large-enough" anonymous mmap region.
+ *
+ * The nice thing about option #2 is that we don't have to traverse
+ * all of the classes and methods twice. The risk is that we might
+ * not make the region large enough. Since the pages aren't mapped
+ * until used we can allocate a semi-absurd amount of memory without
+ * worrying about the effect on the rest of the system.
+ *
+ * The basic encoding on the largest jar file requires about 1MB of
+ * storage. We map out 4MB here. (TODO: guarantee that the last
+ * page of the mapping is marked invalid, so we reliably fail if
+ * we overrun.)
+ */
+ if (sysCreatePrivateMap(4 * 1024 * 1024, &pBuilder->memMap) != 0) {
+ free(pBuilder);
+ return NULL;
+ }
+
+ /*
+ * Create the maps.
+ */
+ size_t actual = writeMapsAllClasses(pDvmDex, (u1*)pBuilder->memMap.addr,
+ pBuilder->memMap.length);
+ if (actual == 0) {
+ dvmFreeRegisterMapBuilder(pBuilder);
+ return NULL;
+ }
+
+ LOGV("TOTAL size of register maps: %d\n", actual);
+
+ pBuilder->data = pBuilder->memMap.addr;
+ pBuilder->size = actual;
+ return pBuilder;
+}
+
+/*
+ * Free the builder.
+ */
+void dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder)
+{
+ if (pBuilder == NULL)
+ return;
+
+ sysReleaseShmem(&pBuilder->memMap);
+ free(pBuilder);
+}
+
+
+/*
+ * Find the data for the specified class.
+ *
+ * If there's no register map data, or none for this class, we return NULL.
+ */
+const void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx,
+ u4* pNumMaps)
+{
+ const RegisterMapClassPool* pClassPool;
+ const RegisterMapMethodPool* pMethodPool;
+
+ pClassPool = (const RegisterMapClassPool*) pDexFile->pRegisterMapPool;
+ if (pClassPool == NULL)
+ return NULL;
+
+ if (classIdx >= pClassPool->numClasses) {
+ LOGE("bad class index (%d vs %d)\n", classIdx, pClassPool->numClasses);
+ dvmAbort();
+ }
+
+ u4 classOffset = pClassPool->classDataOffset[classIdx];
+ if (classOffset == 0) {
+ LOGV("+++ no map for classIdx=%d\n", classIdx);
+ return NULL;
+ }
+
+ pMethodPool =
+ (const RegisterMapMethodPool*) (((u1*) pClassPool) + classOffset);
+ if (pNumMaps != NULL)
+ *pNumMaps = pMethodPool->methodCount;
+ return pMethodPool->methodData;
+}
+
+/*
+ * This advances "*pPtr" and returns its original value.
+ */
+const RegisterMap* dvmRegisterMapGetNext(const void** pPtr)
+{
+ const RegisterMap* pMap = *pPtr;
+
+ *pPtr = /*align32*/(((u1*) pMap) + computeRegisterMapSize(pMap));
+ LOGVV("getNext: %p -> %p (f=0x%x w=%d e=%d)\n",
+ pMap, *pPtr, pMap->format, pMap->regWidth,
+ dvmRegisterMapGetNumEntries(pMap));
+ return pMap;
+}
+
+
+/*
+ * ===========================================================================
+ * Utility functions
+ * ===========================================================================
+ */
+
+/*
+ * Return the data for the specified address, or NULL if not found.
+ *
+ * The result must be released with dvmReleaseRegisterMapLine().
+ */
+const u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr)
+{
+ int addrWidth, lineWidth;
+ u1 format = dvmRegisterMapGetFormat(pMap);
+ u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
+
+ assert(numEntries > 0);
+
+ switch (format) {
+ case kRegMapFormatNone:
+ return NULL;
+ case kRegMapFormatCompact8:
+ addrWidth = 1;
+ break;
+ case kRegMapFormatCompact16:
+ addrWidth = 2;
+ break;
+ default:
+ LOGE("Unknown format %d\n", format);
+ dvmAbort();
+ return NULL;
+ }
+
+ lineWidth = addrWidth + pMap->regWidth;
+
+ /*
+ * Find the appropriate entry. Many maps are very small, some are very
+ * large.
+ */
+ static const int kSearchThreshold = 8;
+ const u1* data;
+ int lineAddr;
+
+ if (numEntries < kSearchThreshold) {
+ int i;
+ data = pMap->data;
+ for (i = numEntries; i > 0; i--) {
+ lineAddr = data[0];
+ if (addrWidth > 1)
+ lineAddr |= data[1] << 8;
+ if (lineAddr == addr)
+ return data + addrWidth;
+
+ data += lineWidth;
+ }
+ } else {
+ int hi, lo, mid;
+
+ lo = 0;
+ hi = numEntries -1;
+
+ while (hi >= lo) {
+ mid = (hi + lo) / 2;
+ data = pMap->data + lineWidth * mid;
+
+ lineAddr = data[0];
+ if (addrWidth > 1)
+ lineAddr |= data[1] << 8;
+
+ if (addr > lineAddr) {
+ lo = mid + 1;
+ } else if (addr < lineAddr) {
+ hi = mid - 1;
+ } else {
+ return data + addrWidth;
+ }
+ }
+ }
+
+ assert(data == pMap->data + lineWidth * numEntries);
+ return NULL;
+}
+
+/*
+ * Compare two register maps.
+ *
+ * Returns 0 if they're equal, nonzero if not.
+ */
+static int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2)
+{
+ size_t size1, size2;
+
+ size1 = computeRegisterMapSize(pMap1);
+ size2 = computeRegisterMapSize(pMap2);
+ if (size1 != size2) {
+ LOGI("compareMaps: size mismatch (%zd vs %zd)\n", size1, size2);
+ return -1;
+ }
+
+ if (memcmp(pMap1, pMap2, size1) != 0) {
+ LOGI("compareMaps: content mismatch\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Get the expanded form of the register map associated with the method.
+ *
+ * If the map is already in one of the uncompressed formats, we return
+ * immediately. Otherwise, we expand the map and replace method's register
+ * map pointer, freeing it if it was allocated on the heap.
+ *
+ * NOTE: this function is not synchronized; external locking is mandatory
+ * (unless we're in the zygote, where single-threaded access is guaranteed).
+ */
+const RegisterMap* dvmGetExpandedRegisterMap0(Method* method)
+{
+ const RegisterMap* curMap = method->registerMap;
+ RegisterMap* newMap;
+
+ if (curMap == NULL)
+ return NULL;
+
+ /* 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) {
+ LOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time\n");
+ dvmAbort();
+ }
+ }
+
+ RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
+ switch (format) {
+ case kRegMapFormatCompact8:
+ case kRegMapFormatCompact16:
+ if (REGISTER_MAP_VERBOSE) {
+ if (dvmRegisterMapGetOnHeap(curMap)) {
+ LOGD("RegMap: already expanded: %s.%s\n",
+ method->clazz->descriptor, method->name);
+ } else {
+ LOGD("RegMap: stored w/o compression: %s.%s\n",
+ method->clazz->descriptor, method->name);
+ }
+ }
+ return curMap;
+ case kRegMapFormatDifferential:
+ newMap = uncompressMapDifferential(curMap);
+ break;
+ default:
+ LOGE("Unknown format %d in dvmGetExpandedRegisterMap\n", format);
+ dvmAbort();
+ }
+
+ if (newMap == NULL) {
+ LOGE("Map failed to uncompress (fmt=%d) %s.%s\n",
+ format, method->clazz->descriptor, method->name);
+ return NULL;
+ }
+
+#ifdef REGISTER_MAP_STATS
+ /*
+ * Gather and display some stats.
+ */
+ {
+ MapStats* pStats = (MapStats*) gDvm.registerMapStats;
+ pStats->numExpandedMaps++;
+ pStats->totalExpandedMapSize += computeRegisterMapSize(newMap);
+ LOGD("RMAP: count=%d size=%d\n",
+ pStats->numExpandedMaps, pStats->totalExpandedMapSize);
+ }
+#endif
+
+ IF_LOGV() {
+ char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+ LOGV("Expanding map -> %s.%s:%s\n",
+ method->clazz->descriptor, method->name, desc);
+ free(desc);
+ }
+
+ /*
+ * Update method, and free compressed map if it was sitting on the heap.
+ */
+ dvmSetRegisterMap(method, newMap);
+
+ if (dvmRegisterMapGetOnHeap(curMap))
+ dvmFreeRegisterMap((RegisterMap*) curMap);
+
+ return newMap;
+}
+
+
+/*
+ * ===========================================================================
+ * Map compression
+ * ===========================================================================
+ */
+
+/*
+Notes on map compression
+
+The idea is to create a compressed form that will be uncompressed before
+use, with the output possibly saved in a cache. This means we can use an
+approach that is unsuited for random access if we choose.
+
+In the event that a map simply does not work with our compression scheme,
+it's reasonable to store the map without compression. In the future we
+may want to have more than one compression scheme, and try each in turn,
+retaining the best. (We certainly want to keep the uncompressed form if it
+turns out to be smaller or even slightly larger than the compressed form.)
+
+Each entry consists of an address and a bit vector. Adjacent entries are
+strongly correlated, suggesting differential encoding.
+
+
+Ideally we would avoid outputting adjacent entries with identical
+bit vectors. However, the register values at a given address do not
+imply anything about the set of valid registers at subsequent addresses.
+We therefore cannot omit an entry.
+
+ If the thread stack has a PC at an address without a corresponding
+ entry in the register map, we must conservatively scan the registers in
+ that thread. This can happen when single-stepping in the debugger,
+ because the debugger is allowed to invoke arbitrary methods when
+ a thread is stopped at a breakpoint. If we can guarantee that a GC
+ thread scan will never happen while the debugger has that thread stopped,
+ then we can lift this restriction and simply omit entries that don't
+ change the bit vector from its previous state.
+
+Each entry advances the address value by at least 1 (measured in 16-bit
+"code units"). Looking at the bootclasspath entries, advancing by 2 units
+is most common. Advances by 1 unit are far less common than advances by
+2 units, but more common than 5, and things fall off rapidly. Gaps of
+up to 220 code units appear in some computationally intensive bits of code,
+but are exceedingly rare.
+
+If we sum up the number of transitions in a couple of ranges in framework.jar:
+ [1,4]: 188998 of 218922 gaps (86.3%)
+ [1,7]: 211647 of 218922 gaps (96.7%)
+Using a 3-bit delta, with one value reserved as an escape code, should
+yield good results for the address.
+
+These results would change dramatically if we reduced the set of GC
+points by e.g. removing instructions like integer divide that are only
+present because they can throw and cause an allocation.
+
+We also need to include an "initial gap", because the first few instructions
+in a method may not be GC points.
+
+
+By observation, many entries simply repeat the previous bit vector, or
+change only one or two bits. (This is with type-precise information;
+the rate of change of bits will be different if live-precise information
+is factored in).
+
+Looking again at adjacent entries in framework.jar:
+ 0 bits changed: 63.0%
+ 1 bit changed: 32.2%
+After that it falls off rapidly, e.g. the number of entries with 2 bits
+changed is usually less than 1/10th of the number of entries with 1 bit
+changed. A solution that allows us to encode 0- or 1- bit changes
+efficiently will do well.
+
+We still need to handle cases where a large number of bits change. We
+probably want a way to drop in a full copy of the bit vector when it's
+smaller than the representation of multiple bit changes.
+
+
+The bit-change information can be encoded as an index that tells the
+decoder to toggle the state. We want to encode the index in as few bits
+as possible, but we need to allow for fairly wide vectors (e.g. we have a
+method with 175 registers). We can deal with this in a couple of ways:
+(1) use an encoding that assumes few registers and has an escape code
+for larger numbers of registers; or (2) use different encodings based
+on how many total registers the method has. The choice depends to some
+extent on whether methods with large numbers of registers tend to modify
+the first 16 regs more often than the others.
+
+The last N registers hold method arguments. If the bytecode is expected
+to be examined in a debugger, "dx" ensures that the contents of these
+registers won't change. Depending upon the encoding format, we may be
+able to take advantage of this. We still have to encode the initial
+state, but we know we'll never have to output a bit change for the last
+N registers.
+
+Considering only methods with 16 or more registers, the "target octant"
+for register changes looks like this:
+ [ 43.1%, 16.4%, 6.5%, 6.2%, 7.4%, 8.8%, 9.7%, 1.8% ]
+As expected, there are fewer changes at the end of the list where the
+arguments are kept, and more changes at the start of the list because
+register values smaller than 16 can be used in compact Dalvik instructions
+and hence are favored for frequently-used values. In general, the first
+octant is considerably more active than later entries, the last octant
+is much less active, and the rest are all about the same.
+
+Looking at all bit changes in all methods, 94% are to registers 0-15. The
+encoding will benefit greatly by favoring the low-numbered registers.
+
+
+Some of the smaller methods have identical maps, and space could be
+saved by simply including a pointer to an earlier definition. This would
+be best accomplished by specifying a "pointer" format value, followed by
+a 3-byte (or ULEB128) offset. Implementing this would probably involve
+generating a hash value for each register map and maintaining a hash table.
+
+In some cases there are repeating patterns in the bit vector that aren't
+adjacent. These could benefit from a dictionary encoding. This doesn't
+really become useful until the methods reach a certain size though,
+and managing the dictionary may incur more overhead than we want.
+
+Large maps can be compressed significantly. The trouble is that, when
+we need to use them, we have to uncompress them onto the heap. We may
+get a better trade-off between storage size and heap usage by refusing to
+compress large maps, so that they can be memory mapped and used directly.
+(OTOH, only about 2% of the maps will ever actually be used.)
+
+
+----- differential format -----
+
+// common header
++00 1B format
++01 1B regWidth
++02 2B numEntries (little-endian)
++04 nB length in bytes of the data that follows, in ULEB128 format
+ (not strictly necessary; allows determination of size w/o full parse)
++05+ 1B initial address (0-127), high bit set if max addr >= 256
++06+ nB initial value for bit vector
+
+// for each entry
++00: CCCCBAAA
+
+ AAA: address difference. Values from 0 to 6 indicate an increment of 1
+ to 7. A value of 7 indicates that the address difference is large,
+ and the next byte is a ULEB128-encoded difference value.
+
+ B: determines the meaning of CCCC.
+
+ CCCC: if B is 0, this is the number of the bit to toggle (0-15).
+ If B is 1, this is a count of the number of changed bits (1-14). A value
+ of 0 means that no bits were changed, and a value of 15 indicates
+ that enough bits were changed that it required less space to output
+ the entire bit vector.
+
++01: (optional) ULEB128-encoded address difference
+
++01+: (optional) one or more ULEB128-encoded bit numbers, OR the entire
+ bit vector.
+
+The most common situation is an entry whose address has changed by 2-4
+code units, has no changes or just a single bit change, and the changed
+register is less than 16. We should therefore be able to encode a large
+number of entries with a single byte, which is half the size of the
+Compact8 encoding method.
+*/
+
+/*
+ * Compute some stats on an uncompressed register map.
+ */
+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);
+ const u1* rawMap = pMap->data;
+ const u1* prevData = NULL;
+ int ent, addr, prevAddr = -1;
+
+ for (ent = 0; ent < numEntries; ent++) {
+ switch (format) {
+ case kRegMapFormatCompact8:
+ addr = *rawMap++;
+ break;
+ case kRegMapFormatCompact16:
+ addr = *rawMap++;
+ addr |= (*rawMap++) << 8;
+ break;
+ default:
+ /* shouldn't happen */
+ LOGE("GLITCH: bad format (%d)", format);
+ dvmAbort();
+ }
+
+ const u1* dataStart = rawMap;
+
+ pStats->totalGcPointCount++;
+
+ /*
+ * Gather "gap size" stats, i.e. the difference in addresses between
+ * successive GC points.
+ */
+ if (prevData != NULL) {
+ assert(prevAddr >= 0);
+ int addrDiff = addr - prevAddr;
+
+ if (addrDiff < 0) {
+ LOGE("GLITCH: address went backward (0x%04x->0x%04x, %s.%s)\n",
+ prevAddr, addr, method->clazz->descriptor, method->name);
+ } else if (addrDiff > kMaxGcPointGap) {
+ if (REGISTER_MAP_VERBOSE) {
+ LOGI("HEY: addrDiff is %d, max %d (0x%04x->0x%04x %s.%s)\n",
+ addrDiff, kMaxGcPointGap, prevAddr, addr,
+ method->clazz->descriptor, method->name);
+ }
+ /* skip this one */
+ } else {
+ pStats->gcPointGap[addrDiff]++;
+ }
+ pStats->gcGapCount++;
+
+
+ /*
+ * Compare bit vectors in adjacent entries. We want to count
+ * up the number of bits that differ (to see if we frequently
+ * change 0 or 1 bits) and get a sense for which part of the
+ * vector changes the most often (near the start, middle, end).
+ *
+ * We only do the vector position quantization if we have at
+ * least 16 registers in the method.
+ */
+ int numDiff = 0;
+ float div = (float) kNumUpdatePosns / method->registersSize;
+ int regByte;
+ for (regByte = 0; regByte < pMap->regWidth; regByte++) {
+ int prev, cur, bit;
+
+ prev = prevData[regByte];
+ cur = dataStart[regByte];
+
+ for (bit = 0; bit < 8; bit++) {
+ if (((prev >> bit) & 1) != ((cur >> bit) & 1)) {
+ numDiff++;
+
+ int bitNum = regByte * 8 + bit;
+
+ if (bitNum < 16)
+ pStats->updateLT16++;
+ else
+ pStats->updateGE16++;
+
+ if (method->registersSize < 16)
+ continue;
+
+ if (bitNum >= method->registersSize) {
+ /* stuff off the end should be zero in both */
+ LOGE("WEIRD: bit=%d (%d/%d), prev=%02x cur=%02x\n",
+ bit, regByte, method->registersSize,
+ prev, cur);
+ assert(false);
+ }
+ int idx = (int) (bitNum * div);
+ if (!(idx >= 0 && idx < kNumUpdatePosns)) {
+ LOGE("FAIL: bitNum=%d (of %d) div=%.3f idx=%d\n",
+ bitNum, method->registersSize, div, idx);
+ assert(false);
+ }
+ pStats->updatePosn[idx]++;
+ }
+ }
+ }
+
+ if (numDiff > kMaxDiffBits) {
+ if (REGISTER_MAP_VERBOSE) {
+ LOGI("WOW: numDiff is %d, max %d\n", numDiff, kMaxDiffBits);
+ }
+ } else {
+ pStats->numDiffBits[numDiff]++;
+ }
+ }
+
+ /* advance to start of next line */
+ rawMap += pMap->regWidth;
+
+ prevAddr = addr;
+ prevData = dataStart;
+ }
+#endif
+}
+
+
+/*
+ * Compute the difference between two bit vectors.
+ *
+ * If "lebOutBuf" is non-NULL, we output the bit indices in ULEB128 format
+ * as we go. Otherwise, we just generate the various counts.
+ *
+ * The bit vectors are compared byte-by-byte, so any unused bits at the
+ * end must be zero.
+ *
+ * Returns the number of bytes required to hold the ULEB128 output.
+ *
+ * If "pFirstBitChanged" or "pNumBitsChanged" are non-NULL, they will
+ * receive the index of the first changed bit and the number of changed
+ * bits, respectively.
+ */
+static int computeBitDiff(const u1* bits1, const u1* bits2, int byteWidth,
+ int* pFirstBitChanged, int* pNumBitsChanged, u1* lebOutBuf)
+{
+ int numBitsChanged = 0;
+ int firstBitChanged = -1;
+ int lebSize = 0;
+ int byteNum;
+
+ /*
+ * Run through the vectors, first comparing them at the byte level. This
+ * will yield a fairly quick result if nothing has changed between them.
+ */
+ for (byteNum = 0; byteNum < byteWidth; byteNum++) {
+ u1 byte1 = *bits1++;
+ u1 byte2 = *bits2++;
+ if (byte1 != byte2) {
+ /*
+ * Walk through the byte, identifying the changed bits.
+ */
+ int bitNum;
+ for (bitNum = 0; bitNum < 8; bitNum++) {
+ if (((byte1 >> bitNum) & 0x01) != ((byte2 >> bitNum) & 0x01)) {
+ int bitOffset = (byteNum << 3) + bitNum;
+
+ if (firstBitChanged < 0)
+ firstBitChanged = bitOffset;
+ numBitsChanged++;
+
+ if (lebOutBuf == NULL) {
+ lebSize += unsignedLeb128Size(bitOffset);
+ } else {
+ u1* curBuf = lebOutBuf;
+ lebOutBuf = writeUnsignedLeb128(lebOutBuf, bitOffset);
+ lebSize += lebOutBuf - curBuf;
+ }
+ }
+ }
+ }
+ }
+
+ if (numBitsChanged > 0)
+ assert(firstBitChanged >= 0);
+
+ if (pFirstBitChanged != NULL)
+ *pFirstBitChanged = firstBitChanged;
+ if (pNumBitsChanged != NULL)
+ *pNumBitsChanged = numBitsChanged;
+
+ return lebSize;
+}
+
+/*
+ * Compress the register map with differential encoding.
+ *
+ * "meth" is only needed for debug output.
+ *
+ * On success, returns a newly-allocated RegisterMap. If the map is not
+ * compatible for some reason, or fails to get smaller, this will return NULL.
+ */
+static RegisterMap* compressMapDifferential(const RegisterMap* pMap,
+ const Method* meth)
+{
+ RegisterMap* pNewMap = NULL;
+ int origSize = computeRegisterMapSize(pMap);
+ u1* tmpBuf = NULL;
+ u1* tmpPtr;
+ int addrWidth, regWidth, numEntries;
+ bool debug = false;
+
+ if (false &&
+ strcmp(meth->clazz->descriptor, "Landroid/text/StaticLayout;") == 0 &&
+ strcmp(meth->name, "generate") == 0)
+ {
+ debug = true;
+ }
+
+ u1 format = dvmRegisterMapGetFormat(pMap);
+ switch (format) {
+ case kRegMapFormatCompact8:
+ addrWidth = 1;
+ break;
+ case kRegMapFormatCompact16:
+ addrWidth = 2;
+ break;
+ default:
+ LOGE("ERROR: can't compress map with format=%d\n", format);
+ goto bail;
+ }
+
+ regWidth = dvmRegisterMapGetRegWidth(pMap);
+ numEntries = dvmRegisterMapGetNumEntries(pMap);
+
+ if (debug) {
+ LOGI("COMPRESS: %s.%s aw=%d rw=%d ne=%d\n",
+ meth->clazz->descriptor, meth->name,
+ addrWidth, regWidth, numEntries);
+ dumpRegisterMap(pMap, -1);
+ }
+
+ if (numEntries <= 1) {
+ LOGV("Can't compress map with 0 or 1 entries\n");
+ goto bail;
+ }
+
+ /*
+ * We don't know how large the compressed data will be. It's possible
+ * for it to expand and become larger than the original. The header
+ * itself is variable-sized, so we generate everything into a temporary
+ * buffer and then copy it to form-fitting storage once we know how big
+ * it will be (and that it's smaller than the original).
+ *
+ * If we use a size that is equal to the size of the input map plus
+ * a value longer than a single entry can possibly expand to, we need
+ * only check for overflow at the end of each entry. The worst case
+ * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
+ * Addresses are 16 bits, so that's (1 + 3 + regWidth).
+ *
+ * The initial address offset and bit vector will take up less than
+ * or equal to the amount of space required when uncompressed -- large
+ * initial offsets are rejected.
+ */
+ tmpBuf = (u1*) malloc(origSize + (1 + 3 + regWidth));
+ if (tmpBuf == NULL)
+ goto bail;
+
+ tmpPtr = tmpBuf;
+
+ const u1* mapData = pMap->data;
+ const u1* prevBits;
+ u2 addr, prevAddr;
+
+ addr = *mapData++;
+ if (addrWidth > 1)
+ addr |= (*mapData++) << 8;
+
+ if (addr >= 128) {
+ LOGV("Can't compress map with starting address >= 128\n");
+ goto bail;
+ }
+
+ /*
+ * Start by writing the initial address and bit vector data. The high
+ * bit of the initial address is used to indicate the required address
+ * width (which the decoder can't otherwise determine without parsing
+ * the compressed data).
+ */
+ *tmpPtr++ = addr | (addrWidth > 1 ? 0x80 : 0x00);
+ memcpy(tmpPtr, mapData, regWidth);
+
+ prevBits = mapData;
+ prevAddr = addr;
+
+ tmpPtr += regWidth;
+ mapData += regWidth;
+
+ /*
+ * Loop over all following entries.
+ */
+ int entry;
+ for (entry = 1; entry < numEntries; entry++) {
+ int addrDiff;
+ u1 key;
+
+ /*
+ * Pull out the address and figure out how to encode it.
+ */
+ addr = *mapData++;
+ if (addrWidth > 1)
+ addr |= (*mapData++) << 8;
+
+ if (debug)
+ LOGI(" addr=0x%04x ent=%d (aw=%d)\n", addr, entry, addrWidth);
+
+ addrDiff = addr - prevAddr;
+ assert(addrDiff > 0);
+ if (addrDiff < 8) {
+ /* small difference, encode in 3 bits */
+ key = addrDiff -1; /* set 00000AAA */
+ if (debug)
+ LOGI(" : small %d, key=0x%02x\n", addrDiff, key);
+ } else {
+ /* large difference, output escape code */
+ key = 0x07; /* escape code for AAA */
+ if (debug)
+ LOGI(" : large %d, key=0x%02x\n", addrDiff, key);
+ }
+
+ int numBitsChanged, firstBitChanged, lebSize;
+
+ lebSize = computeBitDiff(prevBits, mapData, regWidth,
+ &firstBitChanged, &numBitsChanged, NULL);
+
+ if (debug) {
+ LOGI(" : diff fbc=%d nbc=%d ls=%d (rw=%d)\n",
+ firstBitChanged, numBitsChanged, lebSize, regWidth);
+ }
+
+ if (numBitsChanged == 0) {
+ /* set B to 1 and CCCC to zero to indicate no bits were changed */
+ key |= 0x08;
+ if (debug) LOGI(" : no bits changed\n");
+ } else if (numBitsChanged == 1 && firstBitChanged < 16) {
+ /* set B to 0 and CCCC to the index of the changed bit */
+ key |= firstBitChanged << 4;
+ if (debug) LOGI(" : 1 low bit changed\n");
+ } else if (numBitsChanged < 15 && lebSize < regWidth) {
+ /* set B to 1 and CCCC to the number of bits */
+ key |= 0x08 | (numBitsChanged << 4);
+ if (debug) LOGI(" : some bits changed\n");
+ } else {
+ /* set B to 1 and CCCC to 0x0f so we store the entire vector */
+ key |= 0x08 | 0xf0;
+ if (debug) LOGI(" : encode original\n");
+ }
+
+ /*
+ * Encode output. Start with the key, follow with the address
+ * diff (if it didn't fit in 3 bits), then the changed bit info.
+ */
+ *tmpPtr++ = key;
+ if ((key & 0x07) == 0x07)
+ tmpPtr = writeUnsignedLeb128(tmpPtr, addrDiff);
+
+ if ((key & 0x08) != 0) {
+ int bitCount = key >> 4;
+ if (bitCount == 0) {
+ /* nothing changed, no additional output required */
+ } else if (bitCount == 15) {
+ /* full vector is most compact representation */
+ memcpy(tmpPtr, mapData, regWidth);
+ tmpPtr += regWidth;
+ } else {
+ /* write bit indices in LEB128 format */
+ (void) computeBitDiff(prevBits, mapData, regWidth,
+ NULL, NULL, tmpPtr);
+ tmpPtr += lebSize;
+ }
+ } else {
+ /* single-bit changed, value encoded in key byte */
+ }
+
+ prevBits = mapData;
+ prevAddr = addr;
+ mapData += regWidth;
+
+ /*
+ * See if we've run past the original size.
+ */
+ if (tmpPtr - tmpBuf >= origSize) {
+ if (debug) {
+ LOGD("Compressed size >= original (%d vs %d): %s.%s\n",
+ tmpPtr - tmpBuf, origSize,
+ meth->clazz->descriptor, meth->name);
+ }
+ goto bail;
+ }
+ }
+
+ /*
+ * Create a RegisterMap with the contents.
+ *
+ * TODO: consider using a threshold other than merely ">=". We would
+ * get poorer compression but potentially use less native heap space.
+ */
+ static const int kHeaderSize = offsetof(RegisterMap, data);
+ int newDataSize = tmpPtr - tmpBuf;
+ int newMapSize;
+
+ newMapSize = kHeaderSize + unsignedLeb128Size(newDataSize) + newDataSize;
+ if (newMapSize >= origSize) {
+ if (debug) {
+ LOGD("Final comp size >= original (%d vs %d): %s.%s\n",
+ newMapSize, origSize, meth->clazz->descriptor, meth->name);
+ }
+ goto bail;
+ }
+
+ pNewMap = (RegisterMap*) malloc(newMapSize);
+ if (pNewMap == NULL)
+ goto bail;
+ dvmRegisterMapSetFormat(pNewMap, kRegMapFormatDifferential);
+ dvmRegisterMapSetOnHeap(pNewMap, true);
+ dvmRegisterMapSetRegWidth(pNewMap, regWidth);
+ dvmRegisterMapSetNumEntries(pNewMap, numEntries);
+
+ tmpPtr = pNewMap->data;
+ tmpPtr = writeUnsignedLeb128(tmpPtr, newDataSize);
+ memcpy(tmpPtr, tmpBuf, newDataSize);
+
+ if (REGISTER_MAP_VERBOSE) {
+ LOGD("Compression successful (%d -> %d) from aw=%d rw=%d ne=%d\n",
+ computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap),
+ addrWidth, regWidth, numEntries);
+ }
+
+bail:
+ free(tmpBuf);
+ return pNewMap;
+}
+
+/*
+ * Toggle the value of the "idx"th bit in "ptr".
+ */
+static inline void toggleBit(u1* ptr, int idx)
+{
+ ptr[idx >> 3] ^= 1 << (idx & 0x07);
+}
+
+/*
+ * Expand a compressed map to an uncompressed form.
+ *
+ * Returns a newly-allocated RegisterMap on success, or NULL on failure.
+ *
+ * TODO: consider using the linear allocator or a custom allocator with
+ * LRU replacement for these instead of the native heap.
+ */
+static RegisterMap* uncompressMapDifferential(const RegisterMap* pMap)
+{
+ RegisterMap* pNewMap = NULL;
+ static const int kHeaderSize = offsetof(RegisterMap, data);
+ u1 format = dvmRegisterMapGetFormat(pMap);
+ RegisterMapFormat newFormat;
+ int regWidth, numEntries, newAddrWidth, newMapSize;
+
+ if (format != kRegMapFormatDifferential) {
+ LOGE("Not differential (%d)\n", format);
+ goto bail;
+ }
+
+ regWidth = dvmRegisterMapGetRegWidth(pMap);
+ numEntries = dvmRegisterMapGetNumEntries(pMap);
+
+ /* get the data size; we can check this at the end */
+ const u1* srcPtr = pMap->data;
+ int expectedSrcLen = readUnsignedLeb128(&srcPtr);
+ const u1* srcStart = srcPtr;
+
+ /* get the initial address and the 16-bit address flag */
+ int addr = *srcPtr & 0x7f;
+ if ((*srcPtr & 0x80) == 0) {
+ newFormat = kRegMapFormatCompact8;
+ newAddrWidth = 1;
+ } else {
+ newFormat = kRegMapFormatCompact16;
+ newAddrWidth = 2;
+ }
+ srcPtr++;
+
+ /* now we know enough to allocate the new map */
+ if (REGISTER_MAP_VERBOSE) {
+ LOGI("Expanding to map aw=%d rw=%d ne=%d\n",
+ newAddrWidth, regWidth, numEntries);
+ }
+ newMapSize = kHeaderSize + (newAddrWidth + regWidth) * numEntries;
+ pNewMap = (RegisterMap*) malloc(newMapSize);
+ if (pNewMap == NULL)
+ goto bail;
+
+ dvmRegisterMapSetFormat(pNewMap, newFormat);
+ dvmRegisterMapSetOnHeap(pNewMap, true);
+ dvmRegisterMapSetRegWidth(pNewMap, regWidth);
+ dvmRegisterMapSetNumEntries(pNewMap, numEntries);
+
+ /*
+ * Write the start address and initial bits to the new map.
+ */
+ u1* dstPtr = pNewMap->data;
+
+ *dstPtr++ = addr & 0xff;
+ if (newAddrWidth > 1)
+ *dstPtr++ = (u1) (addr >> 8);
+
+ memcpy(dstPtr, srcPtr, regWidth);
+
+ int prevAddr = addr;
+ const u1* prevBits = dstPtr; /* point at uncompressed data */
+
+ dstPtr += regWidth;
+ srcPtr += regWidth;
+
+ /*
+ * Walk through, uncompressing one line at a time.
+ */
+ int entry;
+ for (entry = 1; entry < numEntries; entry++) {
+ int addrDiff;
+ u1 key;
+
+ key = *srcPtr++;
+
+ /* get the address */
+ if ((key & 0x07) == 7) {
+ /* address diff follows in ULEB128 */
+ addrDiff = readUnsignedLeb128(&srcPtr);
+ } else {
+ addrDiff = (key & 0x07) +1;
+ }
+
+ addr = prevAddr + addrDiff;
+ *dstPtr++ = addr & 0xff;
+ if (newAddrWidth > 1)
+ *dstPtr++ = (u1) (addr >> 8);
+
+ /* unpack the bits */
+ if ((key & 0x08) != 0) {
+ int bitCount = (key >> 4);
+ if (bitCount == 0) {
+ /* no bits changed, just copy previous */
+ memcpy(dstPtr, prevBits, regWidth);
+ } else if (bitCount == 15) {
+ /* full copy of bit vector is present; ignore prevBits */
+ memcpy(dstPtr, srcPtr, regWidth);
+ srcPtr += regWidth;
+ } else {
+ /* copy previous bits and modify listed indices */
+ memcpy(dstPtr, prevBits, regWidth);
+ while (bitCount--) {
+ int bitIndex = readUnsignedLeb128(&srcPtr);
+ toggleBit(dstPtr, bitIndex);
+ }
+ }
+ } else {
+ /* copy previous bits and modify the specified one */
+ memcpy(dstPtr, prevBits, regWidth);
+
+ /* one bit, from 0-15 inclusive, was changed */
+ toggleBit(dstPtr, key >> 4);
+ }
+
+ prevAddr = addr;
+ prevBits = dstPtr;
+ dstPtr += regWidth;
+ }
+
+ if (dstPtr - (u1*) pNewMap != newMapSize) {
+ LOGE("ERROR: output %d bytes, expected %d\n",
+ dstPtr - (u1*) pNewMap, newMapSize);
+ goto bail;
+ }
+
+ if (srcPtr - srcStart != expectedSrcLen) {
+ LOGE("ERROR: consumed %d bytes, expected %d\n",
+ srcPtr - srcStart, expectedSrcLen);
+ goto bail;
+ }
+
+ if (REGISTER_MAP_VERBOSE) {
+ LOGD("Expansion successful (%d -> %d)\n",
+ computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap));
+ }
+
+ return pNewMap;
+
+bail:
+ free(pNewMap);
+ return NULL;
+}
+
+
+/*
+ * ===========================================================================
+ * Just-in-time generation
+ * ===========================================================================
+ */
+
+#if 0 /* incomplete implementation; may be removed entirely in the future */
/*
Notes on just-in-time RegisterMap generation
@@ -82,239 +1899,6 @@
an effort should be made to minimize memory use.
*/
-// fwd
-static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data);
-static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap);
-
-/*
- * Generate the register map for a method that has just been verified
- * (i.e. we're doing this as part of verification).
- *
- * For type-precise determination we have all the data we need, so we
- * just need to encode it in some clever fashion.
- *
- * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
- */
-RegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata)
-{
- RegisterMap* pMap = NULL;
- RegisterMap* pResult = NULL;
- RegisterMapFormat format;
- u1 regWidth;
- u1* mapData;
- int i, bytesForAddr, gcPointCount;
- int bufSize;
-
- regWidth = (vdata->method->registersSize + 7) / 8;
- if (vdata->insnsSize < 256) {
- format = kFormatCompact8;
- bytesForAddr = 1;
- } else {
- format = kFormatCompact16;
- bytesForAddr = 2;
- }
-
- /*
- * Count up the number of GC point instructions.
- *
- * NOTE: this does not automatically include the first instruction,
- * since we don't count method entry as a GC point.
- */
- gcPointCount = 0;
- for (i = 0; i < vdata->insnsSize; i++) {
- if (dvmInsnIsGcPoint(vdata->insnFlags, i))
- gcPointCount++;
- }
- if (gcPointCount >= 65536) {
- /* we could handle this, but in practice we don't get near this */
- LOGE("ERROR: register map can't handle %d gc points in one method\n",
- gcPointCount);
- goto bail;
- }
-
- /*
- * Allocate a buffer to hold the map data.
- */
- bufSize = offsetof(RegisterMap, data);
- bufSize += gcPointCount * (bytesForAddr + regWidth);
-
- LOGD("+++ grm: %s.%s (adr=%d gpc=%d rwd=%d bsz=%d)\n",
- vdata->method->clazz->descriptor, vdata->method->name,
- bytesForAddr, gcPointCount, regWidth, bufSize);
-
- pMap = (RegisterMap*) malloc(bufSize);
- pMap->format = format;
- pMap->regWidth = regWidth;
- pMap->numEntries = gcPointCount;
-
- /*
- * Populate it.
- */
- mapData = pMap->data;
- for (i = 0; i < vdata->insnsSize; i++) {
- if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
- assert(vdata->addrRegs[i] != NULL);
- if (format == kFormatCompact8) {
- *mapData++ = i;
- } else /*kFormatCompact16*/ {
- *mapData++ = i & 0xff;
- *mapData++ = i >> 8;
- }
- outputTypeVector(vdata->addrRegs[i], vdata->insnRegCount, mapData);
- mapData += regWidth;
- }
- }
-
- LOGI("mapData=%p pMap=%p bufSize=%d\n", mapData, pMap, bufSize);
- assert(mapData - (const u1*) pMap == bufSize);
-
-#if 1
- if (!verifyMap(vdata, pMap))
- goto bail;
-#endif
-
- pResult = pMap;
-
-bail:
- return pResult;
-}
-
-/*
- * Release the storage held by a RegisterMap.
- */
-void dvmFreeRegisterMap(RegisterMap* pMap)
-{
- if (pMap == NULL)
- return;
-
- free(pMap);
-}
-
-/*
- * Determine if the RegType value is a reference type.
- *
- * Ordinarily we include kRegTypeZero in the "is it a reference"
- * check. There's no value in doing so here, because we know
- * the register can't hold anything but zero.
- */
-static inline bool isReferenceType(RegType type)
-{
- return (type > kRegTypeMAX || type == kRegTypeUninit);
-}
-
-/*
- * Given a line of registers, output a bit vector that indicates whether
- * or not the register holds a reference type (which could be null).
- *
- * We use '1' to indicate it's a reference, '0' for anything else (numeric
- * value, uninitialized data, merge conflict). Register 0 will be found
- * in the low bit of the first byte.
- */
-static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data)
-{
- u1 val = 0;
- int i;
-
- for (i = 0; i < insnRegCount; i++) {
- RegType type = *regs++;
- val >>= 1;
- if (isReferenceType(type))
- val |= 0x80; /* set hi bit */
-
- if ((i & 0x07) == 7)
- *data++ = val;
- }
- if ((i & 0x07) != 0) {
- /* flush bits from last byte */
- val >>= 8 - (i & 0x07);
- *data++ = val;
- }
-}
-
-/*
- * Double-check the map.
- *
- * We run through all of the data in the map, and compare it to the original.
- */
-static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap)
-{
- const u1* data = pMap->data;
- int ent;
-
- for (ent = 0; ent < pMap->numEntries; ent++) {
- int addr;
-
- switch (pMap->format) {
- case kFormatCompact8:
- addr = *data++;
- break;
- case kFormatCompact16:
- addr = *data++;
- addr |= (*data++) << 8;
- break;
- default:
- /* shouldn't happen */
- LOGE("GLITCH: bad format (%d)", pMap->format);
- dvmAbort();
- }
-
- const RegType* regs = vdata->addrRegs[addr];
- if (regs == NULL) {
- LOGE("GLITCH: addr %d has no data\n", addr);
- return false;
- }
-
- u1 val;
- int i;
-
- for (i = 0; i < vdata->method->registersSize; i++) {
- bool bitIsRef, regIsRef;
-
- val >>= 1;
- if ((i & 0x07) == 0) {
- /* load next byte of data */
- val = *data++;
- }
-
- bitIsRef = val & 0x01;
-
- RegType type = regs[i];
- regIsRef = isReferenceType(type);
-
- if (bitIsRef != regIsRef) {
- LOGE("GLITCH: addr %d reg %d: bit=%d reg=%d(%d)\n",
- addr, i, bitIsRef, regIsRef, type);
- return false;
- }
- }
-
- /* print the map as a binary string */
- if (false) {
- char outBuf[vdata->method->registersSize +1];
- for (i = 0; i < vdata->method->registersSize; i++) {
- if (isReferenceType(regs[i])) {
- outBuf[i] = '1';
- } else {
- outBuf[i] = '0';
- }
- }
- outBuf[i] = '\0';
- LOGD(" %04d %s\n", addr, outBuf);
- }
- }
-
- return true;
-}
-
-
-/*
- * ===========================================================================
- * Just-in-time generation
- * ===========================================================================
- */
-
-#if 0 /* incomplete implementation; may be removed entirely in the future */
-
/*
* This is like RegType in the verifier, but simplified. It holds a value
* from the reg type enum, or kRegTypeReference.
diff --git a/vm/analysis/RegisterMap.h b/vm/analysis/RegisterMap.h
index 2a890e7..dc17b1d 100644
--- a/vm/analysis/RegisterMap.h
+++ b/vm/analysis/RegisterMap.h
@@ -14,38 +14,221 @@
* limitations under the License.
*/
-// ** UNDER CONSTRUCTION **
-
/*
* Declaration of register map data structure and related functions.
+ *
+ * These structures should be treated as opaque through most of the VM.
*/
#ifndef _DALVIK_REGISTERMAP
#define _DALVIK_REGISTERMAP
+#include "analysis/VerifySubs.h"
+#include "analysis/CodeVerify.h"
+
/*
* Format enumeration for RegisterMap data area.
*/
typedef enum RegisterMapFormat {
- kFormatUnknown = 0,
- kFormatCompact8, /* compact layout, 8-bit addresses */
- kFormatCompact16, /* compact layout, 16-bit addresses */
- // TODO: compressed stream
+ kRegMapFormatUnknown = 0,
+ kRegMapFormatNone, /* indicates no map data follows */
+ kRegMapFormatCompact8, /* compact layout, 8-bit addresses */
+ kRegMapFormatCompact16, /* compact layout, 16-bit addresses */
+ kRegMapFormatDifferential, /* compressed, differential encoding */
+
+ kRegMapFormatOnHeap = 0x80, /* bit flag, indicates allocation on heap */
} RegisterMapFormat;
/*
* This is a single variable-size structure. It may be allocated on the
* heap or mapped out of a (post-dexopt) DEX file.
+ *
+ * 32-bit alignment of the structure is NOT guaranteed. This makes it a
+ * little awkward to deal with as a structure; to avoid accidents we use
+ * only byte types. Multi-byte values are little-endian.
+ *
+ * Size of (format==FormatNone): 1 byte
+ * Size of (format==FormatCompact8): 4 + (1 + regWidth) * numEntries
+ * Size of (format==FormatCompact16): 4 + (2 + regWidth) * numEntries
*/
struct RegisterMap {
/* header */
- u1 format; /* enum RegisterMapFormat */
+ u1 format; /* enum RegisterMapFormat; MUST be first entry */
u1 regWidth; /* bytes per register line, 1+ */
- u2 numEntries; /* number of entries */
+ u1 numEntries[2]; /* number of entries */
- /* data starts here; no alignment guarantees made */
+ /* raw data starts here; need not be aligned */
u1 data[1];
};
+bool dvmRegisterMapStartup(void);
+void dvmRegisterMapShutdown(void);
+
+/*
+ * Get the format.
+ */
+INLINE RegisterMapFormat dvmRegisterMapGetFormat(const RegisterMap* pMap) {
+ return pMap->format & ~(kRegMapFormatOnHeap);
+}
+
+/*
+ * Set the format.
+ */
+INLINE void dvmRegisterMapSetFormat(RegisterMap* pMap, RegisterMapFormat format)
+{
+ pMap->format &= kRegMapFormatOnHeap;
+ pMap->format |= format;
+}
+
+/*
+ * Get the "on heap" flag.
+ */
+INLINE bool dvmRegisterMapGetOnHeap(const RegisterMap* pMap) {
+ return (pMap->format & kRegMapFormatOnHeap) != 0;
+}
+
+/*
+ * Get the register bit vector width, in bytes.
+ */
+INLINE u1 dvmRegisterMapGetRegWidth(const RegisterMap* pMap) {
+ return pMap->regWidth;
+}
+
+/*
+ * Set the register bit vector width, in bytes.
+ */
+INLINE void dvmRegisterMapSetRegWidth(RegisterMap* pMap, int regWidth) {
+ pMap->regWidth = regWidth;
+}
+
+/*
+ * Set the "on heap" flag.
+ */
+INLINE void dvmRegisterMapSetOnHeap(RegisterMap* pMap, bool val) {
+ if (val)
+ pMap->format |= kRegMapFormatOnHeap;
+ else
+ pMap->format &= ~(kRegMapFormatOnHeap);
+}
+
+/*
+ * Get the number of entries in this map.
+ */
+INLINE u2 dvmRegisterMapGetNumEntries(const RegisterMap* pMap) {
+ return pMap->numEntries[0] | (pMap->numEntries[1] << 8);
+}
+
+/*
+ * Set the number of entries in this map.
+ */
+INLINE void dvmRegisterMapSetNumEntries(RegisterMap* pMap, u2 numEntries) {
+ pMap->numEntries[0] = (u1) numEntries;
+ pMap->numEntries[1] = numEntries >> 8;
+}
+
+/*
+ * Retrieve the bit vector for the specified address. This is a pointer
+ * to the bit data from an uncompressed map, or to a temporary copy of
+ * data from a compressed map.
+ *
+ * The caller must call dvmReleaseRegisterMapLine() with the result.
+ *
+ * Returns NULL if not found.
+ */
+const u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr);
+
+/*
+ * Release "data".
+ *
+ * If "pMap" points to a compressed map from which we have expanded a
+ * single line onto the heap, this will free "data"; otherwise, it does
+ * nothing.
+ *
+ * TODO: decide if this is still a useful concept.
+ */
+INLINE void dvmReleaseRegisterMapLine(const RegisterMap* pMap, const u1* data)
+{}
+
+
+/*
+ * A pool of register maps for methods associated with a single class.
+ *
+ * Each entry is a 4-byte method index followed by the 32-bit-aligned
+ * RegisterMap. The size of the RegisterMap is determined by parsing
+ * the map. The lack of an index reduces random access speed, but we
+ * should be doing that rarely (during class load) and it saves space.
+ *
+ * These structures are 32-bit aligned.
+ */
+typedef struct RegisterMapMethodPool {
+ u2 methodCount; /* chiefly used as a sanity check */
+
+ /* stream of per-method data starts here */
+ u4 methodData[1];
+} RegisterMapMethodPool;
+
+/*
+ * Header for the memory-mapped RegisterMap pool in the DEX file.
+ *
+ * The classDataOffset table provides offsets from the start of the
+ * RegisterMapPool structure. There is one entry per class (including
+ * interfaces, which can have static initializers).
+ *
+ * The offset points to a RegisterMapMethodPool.
+ *
+ * These structures are 32-bit aligned.
+ */
+typedef struct RegisterMapClassPool {
+ u4 numClasses;
+
+ /* offset table starts here, 32-bit aligned; offset==0 means no data */
+ u4 classDataOffset[1];
+} RegisterMapClassPool;
+
+/*
+ * Find the register maps for this class. (Used during class loading.)
+ * If "pNumMaps" is non-NULL, it will return the number of maps in the set.
+ *
+ * Returns NULL if none is available.
+ */
+const void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx,
+ u4* pNumMaps);
+
+/*
+ * Get the register map for the next method. "*pPtr" will be advanced past
+ * the end of the map. (Used during class loading.)
+ *
+ * This should initially be called with the result from
+ * dvmRegisterMapGetClassData().
+ */
+const RegisterMap* dvmRegisterMapGetNext(const void** pPtr);
+
+/*
+ * This holds some meta-data while we construct the set of register maps
+ * for a DEX file.
+ *
+ * In particular, it keeps track of our temporary mmap region so we can
+ * free it later.
+ */
+typedef struct RegisterMapBuilder {
+ /* public */
+ void* data;
+ size_t size;
+
+ /* private */
+ MemMapping memMap;
+} RegisterMapBuilder;
+
+/*
+ * Generate a register map set for all verified classes in "pDvmDex".
+ */
+RegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex);
+
+/*
+ * Free the builder.
+ */
+void dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder);
+
+
/*
* Generate the register map for a previously-verified method.
*
@@ -97,4 +280,31 @@
*/
RegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata);
+/*
+ * Get the expanded form of the register map associated with the specified
+ * method. May update method->registerMap, possibly freeing the previous
+ * map.
+ *
+ * Returns NULL on failure (e.g. unable to expand map).
+ *
+ * NOTE: this function is not synchronized; external locking is mandatory.
+ * (This is expected to be called at GC time.)
+ */
+const RegisterMap* dvmGetExpandedRegisterMap0(Method* method);
+INLINE const RegisterMap* dvmGetExpandedRegisterMap(Method* method)
+{
+ const RegisterMap* curMap = method->registerMap;
+ if (curMap == NULL)
+ return NULL;
+ RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
+ if (format == kRegMapFormatCompact8 || format == kRegMapFormatCompact16) {
+ return curMap;
+ } else {
+ return dvmGetExpandedRegisterMap0(method);
+ }
+}
+
+/* dump stats gathered during register map creation process */
+void dvmRegisterMapDumpStats(void);
+
#endif /*_DALVIK_REGISTERMAP*/
diff --git a/vm/analysis/VerifySubs.h b/vm/analysis/VerifySubs.h
index 4d5b57c..a87c6f1 100644
--- a/vm/analysis/VerifySubs.h
+++ b/vm/analysis/VerifySubs.h
@@ -57,7 +57,11 @@
#define LOG_VFY_METH(_meth, ...) dvmLogVerifyFailure(_meth, __VA_ARGS__)
/* log verification failure with optional method info */
-void dvmLogVerifyFailure(const Method* meth, const char* format, ...);
+void dvmLogVerifyFailure(const Method* meth, const char* format, ...)
+#if defined(__GNUC__)
+ __attribute__ ((format(printf, 2, 3)))
+#endif
+ ;
/* log verification failure due to resolution trouble */
void dvmLogUnableToResolveClass(const char* missingClassDescr,
diff --git a/vm/arch/arm/CallEABI.S b/vm/arch/arm/CallEABI.S
index a98473f..25441f4 100644
--- a/vm/arch/arm/CallEABI.S
+++ b/vm/arch/arm/CallEABI.S
@@ -239,7 +239,12 @@
@ call the method
ldr ip, [r4, #8] @ func
+#ifdef __ARM_HAVE_BLX
blx ip
+#else
+ mov lr, pc
+ bx ip
+#endif
@ We're back, result is in r0 or (for long/double) r0-r1.
@
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
new file mode 100644
index 0000000..f70b978
--- /dev/null
+++ b/vm/compiler/Compiler.c
@@ -0,0 +1,257 @@
+/*
+ * 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 <sys/mman.h>
+#include <errno.h>
+
+#include "Dalvik.h"
+#include "interp/Jit.h"
+#include "CompilerInternals.h"
+
+
+static inline bool workQueueLength(void)
+{
+ return gDvmJit.compilerQueueLength;
+}
+
+static CompilerWorkOrder workDequeue(void)
+{
+ assert(gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex].kind
+ != kWorkOrderInvalid);
+ CompilerWorkOrder work =
+ gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex];
+ gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkDequeueIndex++].kind =
+ kWorkOrderInvalid;
+ if (gDvmJit.compilerWorkDequeueIndex == COMPILER_WORK_QUEUE_SIZE) {
+ gDvmJit.compilerWorkDequeueIndex = 0;
+ }
+ gDvmJit.compilerQueueLength--;
+
+ /* Remember the high water mark of the queue length */
+ if (gDvmJit.compilerQueueLength > gDvmJit.compilerMaxQueued)
+ gDvmJit.compilerMaxQueued = gDvmJit.compilerQueueLength;
+
+ return work;
+}
+
+bool dvmCompilerWorkEnqueue(const u2 *pc, WorkOrderKind kind, void* info)
+{
+ int cc;
+ int i;
+ int numWork;
+
+ dvmLockMutex(&gDvmJit.compilerLock);
+
+ /* Queue full */
+ if (gDvmJit.compilerQueueLength == COMPILER_WORK_QUEUE_SIZE ||
+ gDvmJit.codeCacheFull == true) {
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ return false;
+ }
+
+ for (numWork = gDvmJit.compilerQueueLength,
+ i = gDvmJit.compilerWorkDequeueIndex;
+ numWork > 0;
+ numWork--) {
+ /* Already enqueued */
+ if (gDvmJit.compilerWorkQueue[i++].pc == pc)
+ goto done;
+ /* Wrap around */
+ if (i == COMPILER_WORK_QUEUE_SIZE)
+ i = 0;
+ }
+
+ gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].pc = pc;
+ gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].kind = kind;
+ gDvmJit.compilerWorkQueue[gDvmJit.compilerWorkEnqueueIndex].info = info;
+ gDvmJit.compilerWorkEnqueueIndex++;
+ if (gDvmJit.compilerWorkEnqueueIndex == COMPILER_WORK_QUEUE_SIZE)
+ gDvmJit.compilerWorkEnqueueIndex = 0;
+ gDvmJit.compilerQueueLength++;
+ cc = pthread_cond_signal(&gDvmJit.compilerQueueActivity);
+ assert(cc == 0);
+
+done:
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ return true;
+}
+
+/* Block until queue length is 0 */
+void dvmCompilerDrainQueue(void)
+{
+ dvmLockMutex(&gDvmJit.compilerLock);
+ while (workQueueLength() != 0 && !gDvmJit.haltCompilerThread) {
+ pthread_cond_wait(&gDvmJit.compilerQueueEmpty, &gDvmJit.compilerLock);
+ }
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+}
+
+static void *compilerThreadStart(void *arg)
+{
+ dvmLockMutex(&gDvmJit.compilerLock);
+ /*
+ * Since the compiler thread will not touch any objects on the heap once
+ * being created, we just fake its state as VMWAIT so that it can be a
+ * bit late when there is suspend request pending.
+ */
+ dvmChangeStatus(NULL, THREAD_VMWAIT);
+ while (!gDvmJit.haltCompilerThread) {
+ if (workQueueLength() == 0) {
+ int cc;
+ cc = pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
+ assert(cc == 0);
+ pthread_cond_wait(&gDvmJit.compilerQueueActivity,
+ &gDvmJit.compilerLock);
+ continue;
+ } else {
+ do {
+ void *compiledCodePtr;
+ CompilerWorkOrder work = workDequeue();
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ /* Check whether there is a suspend request on me */
+ dvmCheckSuspendPending(NULL);
+ /* Is JitTable filling up? */
+ if (gDvmJit.jitTableEntriesUsed >
+ (gDvmJit.jitTableSize - gDvmJit.jitTableSize/4)) {
+ dvmJitResizeJitTable(gDvmJit.jitTableSize * 2);
+ }
+ if (gDvmJit.haltCompilerThread) {
+ LOGD("Compiler shutdown in progress - discarding request");
+ } else {
+ compiledCodePtr = dvmCompilerDoWork(&work);
+ /* Compilation is successful */
+ if (compiledCodePtr) {
+ dvmJitSetCodeAddr(work.pc, compiledCodePtr);
+ }
+ }
+ free(work.info);
+ dvmLockMutex(&gDvmJit.compilerLock);
+ } while (workQueueLength() != 0);
+ }
+ }
+ pthread_cond_signal(&gDvmJit.compilerQueueEmpty);
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+
+ LOGD("Compiler thread shutting down\n");
+ return NULL;
+}
+
+bool dvmCompilerSetupCodeCache(void)
+{
+ extern void dvmCompilerTemplateStart(void);
+ extern void dmvCompilerTemplateEnd(void);
+
+ /* Allocate the code cache */
+ gDvmJit.codeCache = mmap(0, CODE_CACHE_SIZE,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (gDvmJit.codeCache == MAP_FAILED) {
+ LOGE("Failed to create the code cache: %s\n", strerror(errno));
+ return false;
+ }
+
+ /* Copy the template code into the beginning of the code cache */
+ int templateSize = (intptr_t) dmvCompilerTemplateEnd -
+ (intptr_t) dvmCompilerTemplateStart;
+ memcpy((void *) gDvmJit.codeCache,
+ (void *) dvmCompilerTemplateStart,
+ templateSize);
+
+ gDvmJit.templateSize = templateSize;
+ gDvmJit.codeCacheByteUsed = templateSize;
+
+ /* Flush dcache and invalidate the icache to maintain coherence */
+ cacheflush((intptr_t) gDvmJit.codeCache,
+ (intptr_t) gDvmJit.codeCache + CODE_CACHE_SIZE, 0);
+ return true;
+}
+
+bool dvmCompilerStartup(void)
+{
+ /* Make sure the BBType enum is in sane state */
+ assert(CHAINING_CELL_NORMAL == 0);
+
+ /* Architecture-specific chores to initialize */
+ if (!dvmCompilerArchInit())
+ goto fail;
+
+ /*
+ * Setup the code cache if it is not done so already. For apps it should be
+ * done by the Zygote already, but for command-line dalvikvm invocation we
+ * need to do it here.
+ */
+ if (gDvmJit.codeCache == NULL) {
+ if (!dvmCompilerSetupCodeCache())
+ goto fail;
+ }
+
+ /* Allocate the initial arena block */
+ if (dvmCompilerHeapInit() == false) {
+ goto fail;
+ }
+
+ dvmInitMutex(&gDvmJit.compilerLock);
+ pthread_cond_init(&gDvmJit.compilerQueueActivity, NULL);
+ pthread_cond_init(&gDvmJit.compilerQueueEmpty, NULL);
+
+ dvmLockMutex(&gDvmJit.compilerLock);
+
+ gDvmJit.haltCompilerThread = false;
+
+ /* Reset the work queue */
+ memset(gDvmJit.compilerWorkQueue, 0,
+ sizeof(CompilerWorkOrder) * COMPILER_WORK_QUEUE_SIZE);
+ gDvmJit.compilerWorkEnqueueIndex = gDvmJit.compilerWorkDequeueIndex = 0;
+ gDvmJit.compilerQueueLength = 0;
+ gDvmJit.compilerHighWater =
+ COMPILER_WORK_QUEUE_SIZE - (COMPILER_WORK_QUEUE_SIZE/4);
+
+ assert(gDvmJit.compilerHighWater < COMPILER_WORK_QUEUE_SIZE);
+ if (!dvmCreateInternalThread(&gDvmJit.compilerHandle, "Compiler",
+ compilerThreadStart, NULL)) {
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+ goto fail;
+ }
+
+ /* Track method-level compilation statistics */
+ gDvmJit.methodStatsTable = dvmHashTableCreate(32, NULL);
+
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+
+ return true;
+
+fail:
+ return false;
+}
+
+void dvmCompilerShutdown(void)
+{
+ void *threadReturn;
+
+ if (gDvmJit.compilerHandle) {
+
+ gDvmJit.haltCompilerThread = true;
+
+ dvmLockMutex(&gDvmJit.compilerLock);
+ pthread_cond_signal(&gDvmJit.compilerQueueActivity);
+ dvmUnlockMutex(&gDvmJit.compilerLock);
+
+ if (pthread_join(gDvmJit.compilerHandle, &threadReturn) != 0)
+ LOGW("Compiler thread join failed\n");
+ else
+ LOGD("Compiler thread has shut down\n");
+ }
+}
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
new file mode 100644
index 0000000..093d48a
--- /dev/null
+++ b/vm/compiler/Compiler.h
@@ -0,0 +1,107 @@
+/*
+ * 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.
+ */
+
+#ifndef _DALVIK_VM_COMPILER
+#define _DALVIK_VM_COMPILER
+
+#define CODE_CACHE_SIZE 1024*1024
+#define MAX_JIT_RUN_LEN 64
+#define COMPILER_WORK_QUEUE_SIZE 100
+
+#define COMPILER_TRACED(X)
+#define COMPILER_TRACEE(X)
+#define COMPILER_TRACE_CHAINING(X)
+
+typedef enum WorkOrderKind {
+ kWorkOrderInvalid = 0, // Should never see by the backend
+ kWorkOrderMethod = 1, // Work is to compile a whole method
+ kWorkOrderTrace = 2, // Work is to compile code fragment(s)
+} WorkOrderKind;
+
+typedef struct CompilerWorkOrder {
+ const u2* pc;
+ WorkOrderKind kind;
+ void* info;
+} CompilerWorkOrder;
+
+typedef enum JitState {
+ kJitOff = 0,
+ kJitNormal = 1, // Profiling in mterp or running native
+ kJitTSelectRequest = 2, // Transition state - start trace selection
+ kJitTSelect = 3, // Actively selecting trace in dbg interp
+ kJitTSelectAbort = 4, // Something threw during selection - abort
+ kJitTSelectEnd = 5, // Done with the trace - wrap it up
+ kJitSingleStep = 6, // Single step interpretation
+ kJitSingleStepEnd = 7, // Done with single step, return to mterp
+} JitState;
+
+typedef enum JitHint {
+ kJitHintNone = 0,
+ kJitHintTaken = 1, // Last inst in run was taken branch
+ kJitHintNotTaken = 2, // Last inst in run was not taken branch
+ kJitHintNoBias = 3, // Last inst in run was unbiased branch
+} 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
+ */
+typedef struct {
+ u2 startOffset; // Starting offset for trace run
+ 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
+} JitCodeDesc;
+
+typedef union {
+ JitCodeDesc frag;
+ void* hint;
+} JitTraceRun;
+
+/*
+ * Trace description as will appear in the translation cache. Note
+ * flexible array at end, as these will be of variable size. To
+ * conserve space in the translation cache, total length of JitTraceRun
+ * array must be recomputed via seqential scan if needed.
+ */
+typedef struct {
+ const Method* method;
+ JitTraceRun trace[];
+} JitTraceDescription;
+
+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
+} CompilerMethodStats;
+
+bool dvmCompilerSetupCodeCache(void);
+bool dvmCompilerArchInit(void);
+void dvmCompilerArchDump(void);
+bool dvmCompilerStartup(void);
+void dvmCompilerShutdown(void);
+bool dvmCompilerWorkEnqueue(const u2* pc, WorkOrderKind kind, void* info);
+void *dvmCheckCodeCache(void *method);
+void *dvmCompileMethod(const Method *method);
+void *dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts);
+void dvmCompilerDumpStats(void);
+void dvmCompilerDrainQueue(void);
+void dvmJitUnchainAll(void);
+
+#endif /* _DALVIK_VM_COMPILER */
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
new file mode 100644
index 0000000..8a2028a
--- /dev/null
+++ b/vm/compiler/CompilerIR.h
@@ -0,0 +1,106 @@
+/*
+ * 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 "codegen/Optimizer.h"
+
+#ifndef _DALVIK_VM_COMPILER_IR
+#define _DALVIK_VM_COMPILER_IR
+
+typedef enum BBType {
+ /* For coding convenience reasons chaining cell types should appear first */
+ CHAINING_CELL_NORMAL = 0,
+ CHAINING_CELL_HOT,
+ CHAINING_CELL_INVOKE,
+ CHAINING_CELL_LAST,
+ DALVIK_BYTECODE,
+ PC_RECONSTRUCTION,
+ EXCEPTION_HANDLING,
+} BBType;
+
+typedef struct ChainCellCounts {
+ union {
+ u1 count[CHAINING_CELL_LAST];
+ u4 dummyForAlignment;
+ } u;
+} ChainCellCounts;
+
+typedef struct LIR {
+ int offset;
+ struct LIR *next;
+ struct LIR *prev;
+ struct LIR *target;
+} LIR;
+
+typedef struct MIR {
+ DecodedInstruction dalvikInsn;
+ unsigned int width;
+ unsigned int offset;
+ struct MIR *prev;
+ struct MIR *next;
+} MIR;
+
+typedef struct BasicBlock {
+ int id;
+ int visited;
+ unsigned int startOffset;
+ const Method *containingMethod; // For blocks from the callee
+ BBType blockType;
+ bool needFallThroughBranch; // For blocks ended due to length limit
+ MIR *firstMIRInsn;
+ MIR *lastMIRInsn;
+ struct BasicBlock *fallThrough;
+ struct BasicBlock *taken;
+ struct BasicBlock *next; // Serial link for book keeping purposes
+} BasicBlock;
+
+typedef struct CompilationUnit {
+ int numInsts;
+ int numBlocks;
+ BasicBlock **blockList;
+ const Method *method;
+ const JitTraceDescription *traceDesc;
+ LIR *firstLIRInsn;
+ LIR *lastLIRInsn;
+ LIR *wordList;
+ LIR *chainCellOffsetLIR;
+ GrowableList pcReconstructionList;
+ int headerSize; // bytes before the first code ptr
+ int dataOffset; // starting offset of literal pool
+ int totalSize; // header + code size
+ unsigned char *codeBuffer;
+ void *baseAddr;
+ bool printMe;
+ bool allSingleStep;
+ bool halveInstCount;
+ bool executionCount; // Add code to count trace executions
+ int numChainingCells[CHAINING_CELL_LAST];
+ LIR *firstChainingLIR[CHAINING_CELL_LAST];
+ RegisterScoreboard registerScoreboard; // Track register dependency
+ int optRound; // round number to tell an LIR's age
+} CompilationUnit;
+
+BasicBlock *dvmCompilerNewBB(BBType blockType);
+
+void dvmCompilerAppendMIR(BasicBlock *bb, MIR *mir);
+
+void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir);
+
+void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR);
+
+/* Debug Utilities */
+void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit);
+
+#endif /* _DALVIK_VM_COMPILER_IR */
diff --git a/vm/compiler/CompilerInternals.h b/vm/compiler/CompilerInternals.h
new file mode 100644
index 0000000..410213a
--- /dev/null
+++ b/vm/compiler/CompilerInternals.h
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+#ifndef _DALVIK_VM_COMPILER_INTERNAL
+#define _DALVIK_VM_COMPILER_INTERNAL
+
+#include "Dalvik.h"
+#include "CompilerUtility.h"
+#include "CompilerIR.h"
+#include "codegen/CompilerCodegen.h"
+#include "interp/Jit.h"
+
+#endif /* _DALVIK_VM_COMPILER_INTERNAL */
diff --git a/vm/compiler/CompilerUtility.h b/vm/compiler/CompilerUtility.h
new file mode 100644
index 0000000..7b4de11
--- /dev/null
+++ b/vm/compiler/CompilerUtility.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+#ifndef _DALVIK_VM_COMPILER_UTILITY
+#define _DALVIK_VM_COMPILER_UTILITY
+
+#define ARENA_DEFAULT_SIZE 4096
+
+/* Allocate the initial memory block for arena-based allocation */
+bool dvmCompilerHeapInit(void);
+
+typedef struct ArenaMemBlock {
+ size_t bytesAllocated;
+ struct ArenaMemBlock *next;
+ char ptr[0];
+} ArenaMemBlock;
+
+void *dvmCompilerNew(size_t size, bool zero);
+
+void dvmCompilerArenaReset(void);
+
+typedef struct GrowableList {
+ size_t numAllocated;
+ size_t numUsed;
+ void **elemList;
+} GrowableList;
+
+void dvmInitGrowableList(GrowableList *gList, size_t initLength);
+void dvmInsertGrowableList(GrowableList *gList, void *elem);
+
+#endif /* _DALVIK_COMPILER_UTILITY */
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
new file mode 100644
index 0000000..76d9312
--- /dev/null
+++ b/vm/compiler/Frontend.c
@@ -0,0 +1,737 @@
+/*
+ * 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 "Dalvik.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+#include "interp/Jit.h"
+#include "CompilerInternals.h"
+
+/*
+ * Parse an instruction, return the length of the instruction
+ */
+static inline int parseInsn(const u2 *codePtr, DecodedInstruction *decInsn,
+ bool printMe)
+{
+ u2 instr = *codePtr;
+ OpCode opcode = instr & 0xff;
+ int insnWidth;
+
+ // Don't parse instruction data
+ if (opcode == OP_NOP && instr != 0) {
+ return 0;
+ } else {
+ insnWidth = gDvm.instrWidth[opcode];
+ if (insnWidth < 0) {
+ insnWidth = -insnWidth;
+ }
+ }
+
+ dexDecodeInstruction(gDvm.instrFormat, codePtr, decInsn);
+ if (printMe) {
+ LOGD("%p: %#06x %s\n", codePtr, opcode, getOpcodeName(opcode));
+ }
+ return insnWidth;
+}
+
+/*
+ * Identify block-ending instructions and collect supplemental information
+ * regarding the following instructions.
+ */
+static inline bool findBlockBoundary(const Method *caller, MIR *insn,
+ unsigned int curOffset,
+ unsigned int *target, bool *isInvoke,
+ const Method **callee)
+{
+ switch (insn->dalvikInsn.opCode) {
+ /* Target is not compile-time constant */
+ case OP_RETURN_VOID:
+ case OP_RETURN:
+ case OP_RETURN_WIDE:
+ case OP_RETURN_OBJECT:
+ case OP_THROW:
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ case OP_INVOKE_VIRTUAL_QUICK:
+ case OP_INVOKE_VIRTUAL_QUICK_RANGE:
+ *isInvoke = true;
+ break;
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_SUPER_RANGE: {
+ int mIndex = caller->clazz->pDvmDex->
+ pResMethods[insn->dalvikInsn.vB]->methodIndex;
+ const Method *calleeMethod =
+ caller->clazz->super->vtable[mIndex];
+
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
+ *target = (unsigned int) calleeMethod->insns;
+ }
+ *isInvoke = true;
+ *callee = calleeMethod;
+ break;
+ }
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_STATIC_RANGE: {
+ const Method *calleeMethod =
+ caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
+
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
+ *target = (unsigned int) calleeMethod->insns;
+ }
+ *isInvoke = true;
+ *callee = calleeMethod;
+ break;
+ }
+ case OP_INVOKE_SUPER_QUICK:
+ case OP_INVOKE_SUPER_QUICK_RANGE: {
+ const Method *calleeMethod =
+ caller->clazz->super->vtable[insn->dalvikInsn.vB];
+
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
+ *target = (unsigned int) calleeMethod->insns;
+ }
+ *isInvoke = true;
+ *callee = calleeMethod;
+ break;
+ }
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_DIRECT_RANGE: {
+ const Method *calleeMethod =
+ caller->clazz->pDvmDex->pResMethods[insn->dalvikInsn.vB];
+ if (calleeMethod && !dvmIsNativeMethod(calleeMethod)) {
+ *target = (unsigned int) calleeMethod->insns;
+ }
+ *isInvoke = true;
+ *callee = calleeMethod;
+ break;
+ }
+ case OP_GOTO:
+ case OP_GOTO_16:
+ case OP_GOTO_32:
+ *target = curOffset + (int) insn->dalvikInsn.vA;
+ break;
+
+ case OP_IF_EQ:
+ case OP_IF_NE:
+ case OP_IF_LT:
+ case OP_IF_GE:
+ case OP_IF_GT:
+ case OP_IF_LE:
+ *target = curOffset + (int) insn->dalvikInsn.vC;
+ break;
+
+ case OP_IF_EQZ:
+ case OP_IF_NEZ:
+ case OP_IF_LTZ:
+ case OP_IF_GEZ:
+ case OP_IF_GTZ:
+ case OP_IF_LEZ:
+ *target = curOffset + (int) insn->dalvikInsn.vB;
+ break;
+
+ default:
+ return false;
+ } return true;
+}
+
+/*
+ * Identify conditional branch instructions
+ */
+static inline bool isUnconditionalBranch(MIR *insn)
+{
+ switch (insn->dalvikInsn.opCode) {
+ case OP_RETURN_VOID:
+ case OP_RETURN:
+ case OP_RETURN_WIDE:
+ case OP_RETURN_OBJECT:
+ case OP_GOTO:
+ case OP_GOTO_16:
+ case OP_GOTO_32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * dvmHashTableLookup() callback
+ */
+static int compareMethod(const CompilerMethodStats *m1,
+ const CompilerMethodStats *m2)
+{
+ return (int) m1->method - (int) m2->method;
+}
+
+/*
+ * 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.
+ */
+static CompilerMethodStats *analyzeMethodBody(const Method *method)
+{
+ const DexCode *dexCode = dvmGetMethodCode(method);
+ const u2 *codePtr = dexCode->insns;
+ const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
+ int insnSize = 0;
+ int hashValue = dvmComputeUtf8Hash(method->name);
+
+ CompilerMethodStats dummyMethodEntry; // For hash table lookup
+ CompilerMethodStats *realMethodEntry; // For hash table storage
+
+ /* For lookup only */
+ dummyMethodEntry.method = method;
+ realMethodEntry = dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+ &dummyMethodEntry,
+ (HashCompareFunc) compareMethod,
+ false);
+
+ /* Part of this method has been compiled before - just return the entry */
+ if (realMethodEntry != NULL) {
+ return realMethodEntry;
+ }
+
+ /*
+ * First time to compile this method - set up a new entry in the hash table
+ */
+ realMethodEntry =
+ (CompilerMethodStats *) calloc(1, sizeof(CompilerMethodStats));
+ realMethodEntry->method = method;
+
+ dvmHashTableLookup(gDvmJit.methodStatsTable, hashValue,
+ realMethodEntry,
+ (HashCompareFunc) compareMethod,
+ true);
+
+ /* Count the number of instructions */
+ while (codePtr < codeEnd) {
+ DecodedInstruction dalvikInsn;
+ int width = parseInsn(codePtr, &dalvikInsn, false);
+
+ /* Terminate when the data section is seen */
+ if (width == 0)
+ break;
+
+ insnSize += width;
+ codePtr += width;
+ }
+
+ realMethodEntry->dalvikSize = insnSize * 2;
+ return realMethodEntry;
+}
+
+/*
+ * Main entry point to start trace compilation. Basic blocks are constructed
+ * first and they will be passed to the codegen routines to convert Dalvik
+ * bytecode into machine code.
+ */
+void *dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts)
+{
+ const DexCode *dexCode = dvmGetMethodCode(desc->method);
+ const JitTraceRun* currRun = &desc->trace[0];
+ unsigned int curOffset = currRun->frag.startOffset;
+ unsigned int numInsts = currRun->frag.numInsts;
+ const u2 *codePtr = dexCode->insns + curOffset;
+ int traceSize = 0; // # of half-words
+ const u2 *startCodePtr = codePtr;
+ BasicBlock *startBB, *curBB, *lastBB;
+ int numBlocks = 0;
+ static int compilationId;
+ CompilationUnit cUnit;
+ CompilerMethodStats *methodStats;
+
+ compilationId++;
+ memset(&cUnit, 0, sizeof(CompilationUnit));
+
+ /* Locate the entry to store compilation statistics for this method */
+ methodStats = analyzeMethodBody(desc->method);
+
+ cUnit.registerScoreboard.nullCheckedRegs =
+ dvmAllocBitVector(desc->method->registersSize, false);
+
+ /* Initialize the printMe flag */
+ cUnit.printMe = gDvmJit.printMe;
+
+ /* Initialize the profile flag */
+ cUnit.executionCount = gDvmJit.profile;
+
+ /* Identify traces that we don't want to compile */
+ if (gDvmJit.methodTable) {
+ int len = strlen(desc->method->clazz->descriptor) +
+ strlen(desc->method->name) + 1;
+ char *fullSignature = dvmCompilerNew(len, true);
+ strcpy(fullSignature, desc->method->clazz->descriptor);
+ strcat(fullSignature, desc->method->name);
+
+ int hashValue = dvmComputeUtf8Hash(fullSignature);
+
+ /*
+ * Doing three levels of screening to see whether we want to skip
+ * compiling this method
+ */
+
+ /* First, check the full "class;method" signature */
+ bool methodFound =
+ dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+ fullSignature, (HashCompareFunc) strcmp,
+ false) !=
+ NULL;
+
+ /* Full signature not found - check the enclosing class */
+ if (methodFound == false) {
+ int hashValue = dvmComputeUtf8Hash(desc->method->clazz->descriptor);
+ methodFound =
+ dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+ (char *) desc->method->clazz->descriptor,
+ (HashCompareFunc) strcmp, false) !=
+ NULL;
+ /* Enclosing class not found - check the method name */
+ if (methodFound == false) {
+ int hashValue = dvmComputeUtf8Hash(desc->method->name);
+ methodFound =
+ dvmHashTableLookup(gDvmJit.methodTable, hashValue,
+ (char *) desc->method->name,
+ (HashCompareFunc) strcmp, false) !=
+ NULL;
+ }
+ }
+
+ /*
+ * Under the following conditions, the trace will be *conservatively*
+ * compiled by only containing single-step instructions to and from the
+ * interpreter.
+ * 1) If includeSelectedMethod == false, the method matches the full or
+ * partial signature stored in the hash table.
+ *
+ * 2) If includeSelectedMethod == true, the method does not match the
+ * full and partial signature stored in the hash table.
+ */
+ if (gDvmJit.includeSelectedMethod != methodFound) {
+ cUnit.allSingleStep = true;
+ } else {
+ /* Compile the trace as normal */
+
+ /* Print the method we cherry picked */
+ if (gDvmJit.includeSelectedMethod == true) {
+ cUnit.printMe = true;
+ }
+ }
+ }
+
+ /* Allocate the first basic block */
+ lastBB = startBB = curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
+ curBB->startOffset = curOffset;
+ curBB->id = numBlocks++;
+
+ if (cUnit.printMe) {
+ LOGD("--------\nCompiler: Building trace for %s, offset 0x%x\n",
+ desc->method->name, curOffset);
+ }
+
+ /*
+ * Analyze the trace descriptor and include up to the maximal number
+ * of Dalvik instructions into the IR.
+ */
+ while (1) {
+ MIR *insn;
+ int width;
+ insn = dvmCompilerNew(sizeof(MIR),false);
+ insn->offset = curOffset;
+ width = parseInsn(codePtr, &insn->dalvikInsn, cUnit.printMe);
+
+ /* The trace should never incude instruction data */
+ assert(width);
+ insn->width = width;
+ traceSize += width;
+ dvmCompilerAppendMIR(curBB, insn);
+ cUnit.numInsts++;
+ /* Instruction limit reached - terminate the trace here */
+ if (cUnit.numInsts >= numMaxInsts) {
+ break;
+ }
+ if (--numInsts == 0) {
+ if (currRun->frag.runEnd) {
+ break;
+ } else {
+ curBB = dvmCompilerNewBB(DALVIK_BYTECODE);
+ lastBB->next = curBB;
+ lastBB = curBB;
+ curBB->id = numBlocks++;
+ currRun++;
+ curOffset = currRun->frag.startOffset;
+ numInsts = currRun->frag.numInsts;
+ curBB->startOffset = curOffset;
+ codePtr = dexCode->insns + curOffset;
+ }
+ } else {
+ curOffset += width;
+ codePtr += width;
+ }
+ }
+
+ /* Convert # of half-word to bytes */
+ methodStats->compiledDalvikSize += traceSize * 2;
+
+ /*
+ * Now scan basic blocks containing real code to connect the
+ * taken/fallthrough links. Also create chaining cells for code not included
+ * in the trace.
+ */
+ for (curBB = startBB; curBB; curBB = curBB->next) {
+ MIR *lastInsn = curBB->lastMIRInsn;
+ /* Hit a pseudo block - exit the search now */
+ if (lastInsn == NULL) {
+ break;
+ }
+ curOffset = lastInsn->offset;
+ unsigned int targetOffset = curOffset;
+ unsigned int fallThroughOffset = curOffset + lastInsn->width;
+ bool isInvoke = false;
+ const Method *callee = NULL;
+
+ findBlockBoundary(desc->method, curBB->lastMIRInsn, curOffset,
+ &targetOffset, &isInvoke, &callee);
+
+ /* Link the taken and fallthrough blocks */
+ BasicBlock *searchBB;
+
+ /* No backward branch in the trace - start searching the next BB */
+ for (searchBB = curBB->next; searchBB; searchBB = searchBB->next) {
+ if (targetOffset == searchBB->startOffset) {
+ curBB->taken = searchBB;
+ }
+ if (fallThroughOffset == searchBB->startOffset) {
+ curBB->fallThrough = searchBB;
+ }
+ }
+
+ 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
+ * to generate an explicit branch at the end of the block to jump to
+ * the chaining cell.
+ */
+ curBB->needFallThroughBranch =
+ (flags & (kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
+ kInstrInvoke)) == 0;
+
+ /* Target block not included in the trace */
+ if (targetOffset != curOffset && curBB->taken == NULL) {
+ if (isInvoke) {
+ lastBB->next = dvmCompilerNewBB(CHAINING_CELL_INVOKE);
+ /* For unconditional branches, request a hot chaining cell */
+ } else {
+ lastBB->next = dvmCompilerNewBB(flags & kInstrUnconditional ?
+ CHAINING_CELL_HOT :
+ CHAINING_CELL_NORMAL);
+ }
+ lastBB = lastBB->next;
+ lastBB->id = numBlocks++;
+ if (isInvoke) {
+ lastBB->startOffset = 0;
+ lastBB->containingMethod = callee;
+ } else {
+ lastBB->startOffset = targetOffset;
+ }
+ curBB->taken = lastBB;
+ }
+
+ /* Fallthrough block not included in the trace */
+ if (!isUnconditionalBranch(lastInsn) && curBB->fallThrough == NULL) {
+ /*
+ * If the chaining cell is after an invoke or
+ * instruction that cannot change the control flow, request a hot
+ * chaining cell.
+ */
+ if (isInvoke || curBB->needFallThroughBranch) {
+ lastBB->next = dvmCompilerNewBB(CHAINING_CELL_HOT);
+ } else {
+ lastBB->next = dvmCompilerNewBB(CHAINING_CELL_NORMAL);
+ }
+ lastBB = lastBB->next;
+ lastBB->id = numBlocks++;
+ lastBB->startOffset = fallThroughOffset;
+ curBB->fallThrough = lastBB;
+ }
+ }
+
+ /* Now create a special block to host PC reconstruction code */
+ lastBB->next = dvmCompilerNewBB(PC_RECONSTRUCTION);
+ lastBB = lastBB->next;
+ lastBB->id = numBlocks++;
+
+ /* And one final block that publishes the PC and raise the exception */
+ lastBB->next = dvmCompilerNewBB(EXCEPTION_HANDLING);
+ lastBB = lastBB->next;
+ lastBB->id = numBlocks++;
+
+ if (cUnit.printMe) {
+ LOGD("TRACEINFO (%d): 0x%08x %s%s 0x%x %d of %d, %d blocks",
+ compilationId,
+ (intptr_t) desc->method->insns,
+ desc->method->clazz->descriptor,
+ desc->method->name,
+ desc->trace[0].frag.startOffset,
+ traceSize,
+ dexCode->insnsSize,
+ numBlocks);
+ }
+
+ BasicBlock **blockList;
+
+ cUnit.method = desc->method;
+ cUnit.traceDesc = desc;
+ cUnit.numBlocks = numBlocks;
+ dvmInitGrowableList(&cUnit.pcReconstructionList, 8);
+ blockList = cUnit.blockList =
+ dvmCompilerNew(sizeof(BasicBlock *) * numBlocks, true);
+
+ int i;
+
+ for (i = 0, curBB = startBB; i < numBlocks; i++) {
+ blockList[i] = curBB;
+ curBB = curBB->next;
+ }
+ /* Make sure all blocks are added to the cUnit */
+ assert(curBB == NULL);
+
+ if (cUnit.printMe) {
+ dvmCompilerDumpCompilationUnit(&cUnit);
+ }
+
+ /* Convert MIR to LIR, etc. */
+ dvmCompilerMIR2LIR(&cUnit);
+
+ /* Convert LIR into machine code. */
+ dvmCompilerAssembleLIR(&cUnit);
+
+ if (cUnit.printMe) {
+ if (cUnit.halveInstCount) {
+ LOGD("Assembler aborted");
+ } else {
+ dvmCompilerCodegenDump(&cUnit);
+ }
+ LOGD("End %s%s, %d Dalvik instructions",
+ desc->method->clazz->descriptor, desc->method->name,
+ cUnit.numInsts);
+ }
+
+ /* Reset the compiler resource pool */
+ dvmCompilerArenaReset();
+
+ /* Free the bit vector tracking null-checked registers */
+ dvmFreeBitVector(cUnit.registerScoreboard.nullCheckedRegs);
+
+ /*
+ * Things have gone smoothly - publish the starting address of
+ * translation's entry point.
+ */
+ if (!cUnit.halveInstCount) {
+ methodStats->nativeSize += cUnit.totalSize;
+ return cUnit.baseAddr + cUnit.headerSize;
+
+ /* Halve the instruction count and retry again */
+ } else {
+ return dvmCompileTrace(desc, cUnit.numInsts / 2);
+ }
+}
+
+/*
+ * 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.
+ */
+void *dvmCompileMethod(const Method *method)
+{
+ const DexCode *dexCode = dvmGetMethodCode(method);
+ const u2 *codePtr = dexCode->insns;
+ const u2 *codeEnd = dexCode->insns + dexCode->insnsSize;
+ int blockID = 0;
+ unsigned int curOffset = 0;
+
+ BasicBlock *firstBlock = dvmCompilerNewBB(DALVIK_BYTECODE);
+ firstBlock->id = blockID++;
+
+ /* Allocate the bit-vector to track the beginning of basic blocks */
+ BitVector *bbStartAddr = dvmAllocBitVector(dexCode->insnsSize+1, false);
+ dvmSetBit(bbStartAddr, 0);
+
+ /*
+ * Sequentially go through every instruction first and put them in a single
+ * basic block. Identify block boundaries at the mean time.
+ */
+ while (codePtr < codeEnd) {
+ MIR *insn = dvmCompilerNew(sizeof(MIR), false);
+ insn->offset = curOffset;
+ int width = parseInsn(codePtr, &insn->dalvikInsn, false);
+ bool isInvoke = false;
+ const Method *callee;
+ insn->width = width;
+
+ /* Terminate when the data section is seen */
+ if (width == 0)
+ break;
+ dvmCompilerAppendMIR(firstBlock, insn);
+ /*
+ * Check whether this is a block ending instruction and whether it
+ * suggests the start of a new block
+ */
+ unsigned int target = curOffset;
+
+ /*
+ * If findBlockBoundary returns true, it means the current instruction
+ * is terminating the current block. If it is a branch, the target
+ * address will be recorded in target.
+ */
+ if (findBlockBoundary(method, insn, curOffset, &target, &isInvoke,
+ &callee)) {
+ dvmSetBit(bbStartAddr, curOffset + width);
+ if (target != curOffset) {
+ dvmSetBit(bbStartAddr, target);
+ }
+ }
+
+ codePtr += width;
+ /* each bit represents 16-bit quantity */
+ curOffset += width;
+ }
+
+ /*
+ * 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.
+ */
+ 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);
+
+ /*
+ * Register the first block onto the list and start split it into block
+ * boundaries from there.
+ */
+ blockList[0] = firstBlock;
+ cUnit.numBlocks = 1;
+
+ int i;
+ for (i = 0; i < numBlocks; i++) {
+ MIR *insn;
+ BasicBlock *curBB = blockList[i];
+ curOffset = curBB->lastMIRInsn->offset;
+
+ for (insn = curBB->firstMIRInsn->next; insn; insn = insn->next) {
+ /* 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++) {
+ if (blockList[j]->firstMIRInsn->offset == insn->offset)
+ break;
+ }
+
+ /* Block not split yet - do it now */
+ if (j == cUnit.numBlocks) {
+ BasicBlock *newBB = dvmCompilerNewBB(DALVIK_BYTECODE);
+ newBB->id = blockID++;
+ newBB->firstMIRInsn = insn;
+ newBB->startOffset = insn->offset;
+ newBB->lastMIRInsn = curBB->lastMIRInsn;
+ curBB->lastMIRInsn = insn->prev;
+ insn->prev->next = NULL;
+ insn->prev = NULL;
+
+ /*
+ * If the insn is not an unconditional branch, set up the
+ * fallthrough link.
+ */
+ if (!isUnconditionalBranch(curBB->lastMIRInsn)) {
+ curBB->fallThrough = newBB;
+ }
+
+ /* enqueue the new block */
+ blockList[cUnit.numBlocks++] = newBB;
+ break;
+ }
+ }
+ }
+ }
+
+ if (numBlocks != cUnit.numBlocks) {
+ LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
+ dvmAbort();
+ }
+
+ dvmFreeBitVector(bbStartAddr);
+
+ /* Connect the basic blocks through the taken links */
+ for (i = 0; i < numBlocks; i++) {
+ BasicBlock *curBB = blockList[i];
+ MIR *insn = curBB->lastMIRInsn;
+ unsigned int target = insn->offset;
+ bool isInvoke;
+ const Method *callee;
+
+ findBlockBoundary(method, insn, target, &target, &isInvoke, &callee);
+
+ /* Found a block ended on a branch */
+ if (target != insn->offset) {
+ int j;
+ /* Forward branch */
+ if (target > insn->offset) {
+ j = i + 1;
+ } else {
+ /* Backward branch */
+ j = 0;
+ }
+ for (; j < numBlocks; j++) {
+ if (blockList[j]->firstMIRInsn->offset == target) {
+ curBB->taken = blockList[j];
+ 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);
+ dvmAbort();
+ }
+ }
+ }
+
+ dvmCompilerMIR2LIR(&cUnit);
+
+ dvmCompilerAssembleLIR(&cUnit);
+
+ dvmCompilerDumpCompilationUnit(&cUnit);
+
+ dvmCompilerArenaReset();
+
+ return cUnit.baseAddr + cUnit.headerSize;
+}
diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c
new file mode 100644
index 0000000..91b7af7
--- /dev/null
+++ b/vm/compiler/IntermediateRep.c
@@ -0,0 +1,77 @@
+/*
+ * 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 "Dalvik.h"
+#include "CompilerInternals.h"
+
+/* Allocate a new basic block */
+BasicBlock *dvmCompilerNewBB(BBType blockType)
+{
+ BasicBlock *bb = dvmCompilerNew(sizeof(BasicBlock), true);
+ bb->blockType = blockType;
+ return bb;
+}
+
+/* Insert an MIR instruction to the end of a basic block */
+void dvmCompilerAppendMIR(BasicBlock *bb, MIR *mir)
+{
+ if (bb->firstMIRInsn == NULL) {
+ assert(bb->firstMIRInsn == NULL);
+ bb->lastMIRInsn = bb->firstMIRInsn = mir;
+ mir->prev = mir->next = NULL;
+ } else {
+ bb->lastMIRInsn->next = mir;
+ mir->prev = bb->lastMIRInsn;
+ mir->next = NULL;
+ bb->lastMIRInsn = mir;
+ }
+}
+
+/*
+ * Append an LIR instruction to the LIR list maintained by a compilation
+ * unit
+ */
+void dvmCompilerAppendLIR(CompilationUnit *cUnit, LIR *lir)
+{
+ if (cUnit->firstLIRInsn == NULL) {
+ assert(cUnit->lastLIRInsn == NULL);
+ cUnit->lastLIRInsn = cUnit->firstLIRInsn = lir;
+ lir->prev = lir->next = NULL;
+ } else {
+ cUnit->lastLIRInsn->next = lir;
+ lir->prev = cUnit->lastLIRInsn;
+ lir->next = NULL;
+ cUnit->lastLIRInsn = lir;
+ }
+}
+
+/*
+ * Insert an LIR instruction before the current instruction, which cannot be the
+ * first instruction.
+ *
+ * prevLIR <-> newLIR <-> currentLIR
+ */
+void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR)
+{
+ if (currentLIR->prev == NULL)
+ dvmAbort();
+ LIR *prevLIR = currentLIR->prev;
+
+ prevLIR->next = newLIR;
+ newLIR->prev = prevLIR;
+ newLIR->next = currentLIR;
+ currentLIR->prev = newLIR;
+}
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
new file mode 100644
index 0000000..b0c40e6
--- /dev/null
+++ b/vm/compiler/Utility.c
@@ -0,0 +1,209 @@
+/*
+ * 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 "Dalvik.h"
+#include "CompilerInternals.h"
+
+static ArenaMemBlock *arenaHead, *currentArena;
+static int numArenaBlocks;
+
+/* Allocate the initial memory block for arena-based allocation */
+bool dvmCompilerHeapInit(void)
+{
+ assert(arenaHead == NULL);
+ arenaHead =
+ (ArenaMemBlock *) malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
+ if (arenaHead == NULL) {
+ LOGE("No memory left to create compiler heap memory\n");
+ return false;
+ }
+ currentArena = arenaHead;
+ currentArena->bytesAllocated = 0;
+ currentArena->next = NULL;
+ numArenaBlocks = 1;
+
+ return true;
+}
+
+/* Arena-based malloc for compilation tasks */
+void * dvmCompilerNew(size_t size, bool zero)
+{
+ size = (size + 3) & ~3;
+retry:
+ /* Normal case - space is available in the current page */
+ if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) {
+ void *ptr;
+ ptr = ¤tArena->ptr[currentArena->bytesAllocated];
+ currentArena->bytesAllocated += size;
+ if (zero) {
+ memset(ptr, 0, size);
+ }
+ return ptr;
+ } else {
+ /*
+ * See if there are previously allocated arena blocks before the last
+ * reset
+ */
+ if (currentArena->next) {
+ 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.
+ */
+ if (size > ARENA_DEFAULT_SIZE) {
+ LOGE("Requesting %d bytes which exceed the maximal size allowed\n",
+ size);
+ return NULL;
+ }
+ /* Time to allocate a new arena */
+ ArenaMemBlock *newArena = (ArenaMemBlock *)
+ malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
+ newArena->bytesAllocated = 0;
+ newArena->next = NULL;
+ currentArena->next = newArena;
+ currentArena = newArena;
+ numArenaBlocks++;
+ LOGD("Total arena pages for JIT: %d", numArenaBlocks);
+ goto retry;
+ }
+ return NULL;
+}
+
+/* Reclaim all the arena blocks allocated so far */
+void dvmCompilerArenaReset(void)
+{
+ ArenaMemBlock *block;
+
+ for (block = arenaHead; block; block = block->next) {
+ block->bytesAllocated = 0;
+ }
+ currentArena = arenaHead;
+}
+
+/* Growable List initialization */
+void dvmInitGrowableList(GrowableList *gList, size_t initLength)
+{
+ gList->numAllocated = initLength;
+ gList->numUsed = 0;
+ gList->elemList = (void **) dvmCompilerNew(sizeof(void *) * initLength,
+ true);
+}
+
+/* Expand the capacity of a growable list */
+static void expandGrowableList(GrowableList *gList)
+{
+ int newLength = gList->numAllocated;
+ if (newLength < 128) {
+ newLength <<= 1;
+ } else {
+ newLength += 128;
+ }
+ void *newArray = dvmCompilerNew(sizeof(void *) * newLength, true);
+ memcpy(newArray, gList->elemList, sizeof(void *) * gList->numAllocated);
+ gList->numAllocated = newLength;
+ gList->elemList = newArray;
+}
+
+/* Insert a new element into the growable list */
+void dvmInsertGrowableList(GrowableList *gList, void *elem)
+{
+ if (gList->numUsed == gList->numAllocated) {
+ expandGrowableList(gList);
+ }
+ gList->elemList[gList->numUsed++] = elem;
+}
+
+/* Debug Utility - dump a compilation unit */
+void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
+{
+ int i;
+ BasicBlock *bb;
+ LOGD("%d blocks in total\n", 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,
+ bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
+ bb->lastMIRInsn ? "" : " empty");
+ if (bb->taken) {
+ LOGD(" Taken branch: block %d (%04x)\n",
+ bb->taken->id, bb->taken->startOffset);
+ }
+ if (bb->fallThrough) {
+ LOGD(" Fallthrough : block %d (%04x)\n",
+ bb->fallThrough->id, bb->fallThrough->startOffset);
+ }
+ }
+}
+
+/*
+ * dvmHashForeach callback.
+ */
+static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
+{
+ CompilerMethodStats *methodStats =
+ (CompilerMethodStats *) compilerMethodStats;
+ CompilerMethodStats *totalStats =
+ (CompilerMethodStats *) totalMethodStats;
+ const Method *method = methodStats->method;
+
+ totalStats->dalvikSize += methodStats->dalvikSize;
+ totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
+ totalStats->nativeSize += methodStats->nativeSize;
+
+ int limit = (methodStats->dalvikSize >> 2) * 3;
+
+ /* 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->compiledDalvikSize,
+ methodStats->dalvikSize,
+ methodStats->nativeSize);
+ }
+ return 0;
+}
+
+/*
+ * Dump the current stats of the compiler, including number of bytes used in
+ * the code cache, arena size, and work queue length, and various JIT stats.
+ */
+void dvmCompilerDumpStats(void)
+{
+ CompilerMethodStats totalMethodStats;
+
+ memset(&totalMethodStats, 0, sizeof(CompilerMethodStats));
+ LOGD("%d compilations using %d + %d bytes",
+ gDvmJit.numCompilations,
+ gDvmJit.templateSize,
+ gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
+ LOGD("Compiler arena uses %d blocks (%d bytes each)",
+ numArenaBlocks, ARENA_DEFAULT_SIZE);
+ LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength,
+ gDvmJit.compilerMaxQueued);
+ dvmJitStats();
+ dvmCompilerArchDump();
+ dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
+ &totalMethodStats);
+ 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
new file mode 100644
index 0000000..97077b4
--- /dev/null
+++ b/vm/compiler/codegen/CompilerCodegen.h
@@ -0,0 +1,37 @@
+/*
+ * 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 "../CompilerIR.h"
+
+#ifndef _DALVIK_VM_COMPILERCODEGEN_H_
+#define _DALVIK_VM_COMPILERCODEGEN_H_
+
+/* Work unit is architecture dependent */
+void *dvmCompilerDoWork(CompilerWorkOrder *work);
+
+/* Lower middle-level IR to low-level IR */
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit);
+
+/* Assemble LIR into machine code */
+void dvmCompilerAssembleLIR(CompilationUnit *cUnit);
+
+/* Implemented in the codegen/<target>/ArchUtility.c */
+void dvmCompilerCodegenDump(CompilationUnit *cUnit);
+
+/* Implemented in the codegen/<target>/Assembler.c */
+void* dvmJitChain(void *tgtAddr, u4* branchAddr);
+
+#endif /* _DALVIK_VM_COMPILERCODEGEN_H_ */
diff --git a/vm/compiler/codegen/Optimizer.h b/vm/compiler/codegen/Optimizer.h
new file mode 100644
index 0000000..1a891b1
--- /dev/null
+++ b/vm/compiler/codegen/Optimizer.h
@@ -0,0 +1,47 @@
+/*
+ * 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 "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+
+#ifndef _DALVIK_VM_COMPILER_OPTIMIZATION_H
+#define _DALVIK_VM_COMPILER_OPTIMIZATION_H
+
+/* Forward declarations */
+struct CompilationUnit;
+struct LIR;
+
+/*
+ * Data structure tracking the mapping between a Dalvik register (pair) and a
+ * native register (pair). The idea is to reuse the previously loaded value
+ * if possible, otherwise to keep the value in a native register as long as
+ * possible.
+ */
+typedef struct RegisterScoreboard {
+ BitVector *nullCheckedRegs; // Track which registers have been null-checked
+ int liveDalvikReg; // Track which Dalvik register is live
+ int nativeReg; // And the mapped native register
+ int nativeRegHi; // And the mapped native register
+ bool isWide; // Whether a pair of registers are alive
+} RegisterScoreboard;
+
+void dvmCompilerApplyLocalOptimizations(struct CompilationUnit *cUnit,
+ struct LIR *head,
+ struct LIR *tail);
+
+void dvmCompilerApplyGlobalOptimizations(struct CompilationUnit *cUnit);
+
+#endif /* _DALVIK_VM_COMPILER_OPTIMIZATION_H */
diff --git a/vm/compiler/codegen/armv5te/ArchUtility.c b/vm/compiler/codegen/armv5te/ArchUtility.c
new file mode 100644
index 0000000..7d7f119
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/ArchUtility.c
@@ -0,0 +1,227 @@
+/*
+ * 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 "../../CompilerInternals.h"
+#include "dexdump/OpCodeNames.h"
+#include "Armv5teLIR.h"
+
+/* Decode and print a ARM register name */
+static char * decodeRegList(int vector, char *buf)
+{
+ int i;
+ bool printed = false;
+ buf[0] = 0;
+ for (i = 0; i < 8; i++, vector >>= 1) {
+ if (vector & 0x1) {
+ if (printed) {
+ sprintf(buf + strlen(buf), ", r%d", i);
+ } else {
+ printed = true;
+ sprintf(buf, "r%d", i);
+ }
+ }
+ }
+ return buf;
+}
+
+/*
+ * Interpret a format string and build a string no longer than size
+ * See format key in Assemble.c.
+ */
+static void buildInsnString(char *fmt, Armv5teLIR *lir, char* buf,
+ unsigned char *baseAddr, int size)
+{
+ int i;
+ char *bufEnd = &buf[size-1];
+ char *fmtEnd = &fmt[strlen(fmt)];
+ char tbuf[256];
+ char nc;
+ while (fmt < fmtEnd) {
+ int operand;
+ if (*fmt == '!') {
+ fmt++;
+ assert(fmt < fmtEnd);
+ nc = *fmt++;
+ if (nc=='!') {
+ strcpy(tbuf, "!");
+ } else {
+ assert(fmt < fmtEnd);
+ assert((unsigned)(nc-'0') < 3);
+ operand = lir->operands[nc-'0'];
+ switch(*fmt++) {
+ case 'h':
+ sprintf(tbuf,"%04x", operand);
+ break;
+ case 'd':
+ sprintf(tbuf,"%d", operand);
+ break;
+ case 'D':
+ sprintf(tbuf,"%d", operand+8);
+ break;
+ case 'E':
+ sprintf(tbuf,"%d", operand*4);
+ break;
+ case 'F':
+ sprintf(tbuf,"%d", operand*2);
+ break;
+ case 'c':
+ switch (operand) {
+ case ARM_COND_EQ:
+ strcpy(tbuf, "beq");
+ break;
+ case ARM_COND_NE:
+ strcpy(tbuf, "bne");
+ break;
+ case ARM_COND_LT:
+ strcpy(tbuf, "blt");
+ break;
+ case ARM_COND_GE:
+ strcpy(tbuf, "bge");
+ break;
+ case ARM_COND_GT:
+ strcpy(tbuf, "bgt");
+ break;
+ case ARM_COND_LE:
+ strcpy(tbuf, "ble");
+ break;
+ case ARM_COND_CS:
+ strcpy(tbuf, "bcs");
+ break;
+ default:
+ strcpy(tbuf, "");
+ break;
+ }
+ break;
+ case 't':
+ sprintf(tbuf,"0x%08x",
+ (int) baseAddr + lir->generic.offset + 4 +
+ (operand << 1));
+ break;
+ case 'u': {
+ int offset_1 = lir->operands[0];
+ int offset_2 = NEXT_LIR(lir)->operands[0];
+ intptr_t target =
+ ((((intptr_t) baseAddr + lir->generic.offset + 4) &
+ ~3) + (offset_1 << 21 >> 9) + (offset_2 << 1)) &
+ 0xfffffffc;
+ sprintf(tbuf, "%p", (void *) target);
+ break;
+ }
+
+ /* Nothing to print for BLX_2 */
+ case 'v':
+ strcpy(tbuf, "see above");
+ break;
+ case 'R':
+ decodeRegList(operand, tbuf);
+ break;
+ default:
+ strcpy(tbuf,"DecodeError");
+ break;
+ }
+ if (buf+strlen(tbuf) <= bufEnd) {
+ strcpy(buf, tbuf);
+ buf += strlen(tbuf);
+ } else {
+ break;
+ }
+ }
+ } else {
+ *buf++ = *fmt++;
+ }
+ if (buf == bufEnd)
+ break;
+ }
+ *buf = 0;
+}
+
+/* Pretty-print a LIR instruction */
+static void dumpLIRInsn(LIR *arg, unsigned char *baseAddr)
+{
+ Armv5teLIR *lir = (Armv5teLIR *) arg;
+ char buf[256];
+ char opName[256];
+ int offset = lir->generic.offset;
+ int dest = lir->operands[0];
+ u2 *cPtr = (u2*)baseAddr;
+ /* Handle pseudo-ops individually, and all regular insns as a group */
+ switch(lir->opCode) {
+ case ARMV5TE_PSEUDO_TARGET_LABEL:
+ break;
+ case ARMV5TE_PSEUDO_CHAINING_CELL_NORMAL:
+ LOGD("-------- chaining cell (normal): 0x%04x\n", dest);
+ break;
+ case ARMV5TE_PSEUDO_CHAINING_CELL_HOT:
+ LOGD("-------- chaining cell (hot): 0x%04x\n", dest);
+ break;
+ case ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE:
+ LOGD("-------- chaining cell (invoke): %s/%p\n",
+ ((Method *)dest)->name,
+ ((Method *)dest)->insns);
+ break;
+ case ARMV5TE_PSEUDO_DALVIK_BYTECODE_BOUNDARY:
+ LOGD("-------- dalvik offset: 0x%04x @ %s\n", dest,
+ getOpcodeName(lir->operands[1]));
+ break;
+ case ARMV5TE_PSEUDO_ALIGN4:
+ LOGD("%p (%04x): .align4\n", baseAddr + offset, offset);
+ break;
+ case ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL:
+ LOGD("-------- reconstruct dalvik PC : 0x%04x @ +0x%04x\n", dest,
+ lir->operands[1]);
+ break;
+ case ARMV5TE_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL:
+ /* Do nothing */
+ break;
+ case ARMV5TE_PSEUDO_EH_BLOCK_LABEL:
+ LOGD("Exception_Handling:\n");
+ break;
+ case ARMV5TE_PSEUDO_NORMAL_BLOCK_LABEL:
+ LOGD("L%#06x:\n", dest);
+ break;
+ default:
+ if (lir->isNop) {
+ break;
+ }
+ buildInsnString(EncodingMap[lir->opCode].name, lir, opName,
+ baseAddr, 256);
+ buildInsnString(EncodingMap[lir->opCode].fmt, lir, buf, baseAddr,
+ 256);
+ LOGD("%p (%04x): %-8s%s\n",
+ baseAddr + offset, offset, opName, buf);
+ break;
+ }
+}
+
+/* Dump instructions and constant pool contents */
+void dvmCompilerCodegenDump(CompilationUnit *cUnit)
+{
+ LOGD("Dumping LIR insns\n");
+ LIR *lirInsn;
+ Armv5teLIR *armLIR;
+
+ LOGD("installed code is at %p\n", cUnit->baseAddr);
+ LOGD("total size is %d bytes\n", cUnit->totalSize);
+ for (lirInsn = cUnit->firstLIRInsn; lirInsn; lirInsn = lirInsn->next) {
+ dumpLIRInsn(lirInsn, cUnit->baseAddr);
+ }
+ for (lirInsn = cUnit->wordList; lirInsn; lirInsn = lirInsn->next) {
+ armLIR = (Armv5teLIR *) lirInsn;
+ LOGD("%p (%04x): .word (0x%x)\n",
+ cUnit->baseAddr + armLIR->generic.offset, armLIR->generic.offset,
+ armLIR->operands[0]);
+ }
+}
diff --git a/vm/compiler/codegen/armv5te/Armv5teLIR.h b/vm/compiler/codegen/armv5te/Armv5teLIR.h
new file mode 100644
index 0000000..f0a3f42
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/Armv5teLIR.h
@@ -0,0 +1,221 @@
+/*
+ * 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 "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+
+#ifndef _DALVIK_VM_COMPILER_CODEGEN_ARMV5TE_H
+#define _DALVIK_VM_COMPILER_CODEGEN_ARMV5TE_H
+
+/*
+ * r0, r1, r2, r3, and r7 are always scratch
+ * r4PC is scratch if used solely in the compiled land. Otherwise it holds the
+ * Dalvik PC.
+ * rFP holds the current frame pointer
+ * rGLUE holds &InterpState
+ */
+typedef enum NativeRegisterPool {
+ r0 = 0,
+ r1 = 1,
+ r2 = 2,
+ r3 = 3,
+ r4PC = 4,
+ rFP = 5,
+ rGLUE = 6,
+ r7 = 7,
+ r8 = 8,
+ r9 = 9,
+ r10 = 10,
+ r11 = 11,
+ r12 = 12,
+ r13 = 13,
+ rlr = 14,
+ rpc = 15
+} NativeRegisterPool;
+
+/* Mask to convert high reg to low for Thumb */
+#define THUMB_REG_MASK 0x7
+
+/* Thumb condition encodings */
+typedef enum Armv5teConditionCode {
+ ARM_COND_EQ = 0x0, /* 0000 */
+ ARM_COND_NE = 0x1, /* 0001 */
+ ARM_COND_LT = 0xb, /* 1011 */
+ ARM_COND_GE = 0xa, /* 1010 */
+ ARM_COND_GT = 0xc, /* 1100 */
+ ARM_COND_LE = 0xd, /* 1101 */
+ ARM_COND_CS = 0x2, /* 0010 */
+ ARM_COND_MI = 0x4, /* 0100 */
+} Armv5teConditionCode;
+
+#define isPseudoOpCode(opCode) ((int)(opCode) < 0)
+
+/*
+ * The following enum defines the list of supported Thumb instructions by the
+ * assembler. Their corresponding snippet positions will be defined in
+ * Assemble.c.
+ */
+typedef enum Armv5teOpCode {
+ ARMV5TE_PSEUDO_TARGET_LABEL = -10,
+ ARMV5TE_PSEUDO_CHAINING_CELL_HOT = -9,
+ ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE = -8,
+ ARMV5TE_PSEUDO_CHAINING_CELL_NORMAL = -7,
+ ARMV5TE_PSEUDO_DALVIK_BYTECODE_BOUNDARY = -6,
+ ARMV5TE_PSEUDO_ALIGN4 = -5,
+ ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL = -4,
+ ARMV5TE_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL = -3,
+ ARMV5TE_PSEUDO_EH_BLOCK_LABEL = -2,
+ ARMV5TE_PSEUDO_NORMAL_BLOCK_LABEL = -1,
+ /************************************************************************/
+ ARMV5TE_16BIT_DATA, /* DATA [0] rd[15..0] */
+ ARMV5TE_ADC, /* adc [0100000101] rm[5..3] rd[2..0] */
+ ARMV5TE_ADD_RRI3, /* add(1) [0001110] imm_3[8..6] rn[5..3] rd[2..0]*/
+ ARMV5TE_ADD_RI8, /* add(2) [00110] rd[10..8] imm_8[7..0] */
+ ARMV5TE_ADD_RRR, /* add(3) [0001100] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_ADD_RR_LH, /* add(4) [01000100] H12[01] rm[5..3] rd[2..0] */
+ ARMV5TE_ADD_RR_HL, /* add(4) [01001000] H12[10] rm[5..3] rd[2..0] */
+ ARMV5TE_ADD_RR_HH, /* add(4) [01001100] H12[11] rm[5..3] rd[2..0] */
+ ARMV5TE_ADD_PC_REL, /* add(5) [10100] rd[10..8] imm_8[7..0] */
+ ARMV5TE_ADD_SP_REL, /* add(6) [10101] rd[10..8] imm_8[7..0] */
+ ARMV5TE_ADD_SPI7, /* add(7) [101100000] imm_7[6..0] */
+ ARMV5TE_AND_RR, /* and [0100000000] rm[5..3] rd[2..0] */
+ ARMV5TE_ASR, /* asr(1) [00010] imm_5[10..6] rm[5..3] rd[2..0] */
+ ARMV5TE_ASRV, /* asr(2) [0100000100] rs[5..3] rd[2..0] */
+ ARMV5TE_B_COND, /* b(1) [1101] cond[11..8] offset_8[7..0] */
+ ARMV5TE_B_UNCOND, /* b(2) [11100] offset_11[10..0] */
+ ARMV5TE_BIC, /* bic [0100001110] rm[5..3] rd[2..0] */
+ ARMV5TE_BKPT, /* bkpt [10111110] imm_8[7..0] */
+ ARMV5TE_BLX_1, /* blx(1) [111] H[10] offset_11[10..0] */
+ ARMV5TE_BLX_2, /* blx(1) [111] H[01] offset_11[10..0] */
+ ARMV5TE_BL_1, /* blx(1) [111] H[10] offset_11[10..0] */
+ ARMV5TE_BL_2, /* blx(1) [111] H[11] offset_11[10..0] */
+ ARMV5TE_BLX_R, /* blx(2) [010001111] H2[6..6] rm[5..3] SBZ[000] */
+ ARMV5TE_BX, /* bx [010001110] H2[6..6] rm[5..3] SBZ[000] */
+ ARMV5TE_CMN, /* cmn [0100001011] rm[5..3] rd[2..0] */
+ ARMV5TE_CMP_RI8, /* cmp(1) [00101] rn[10..8] imm_8[7..0] */
+ ARMV5TE_CMP_RR, /* cmp(2) [0100001010] rm[5..3] rd[2..0] */
+ ARMV5TE_CMP_LH, /* cmp(3) [01000101] H12[01] rm[5..3] rd[2..0] */
+ ARMV5TE_CMP_HL, /* cmp(3) [01000110] H12[10] rm[5..3] rd[2..0] */
+ ARMV5TE_CMP_HH, /* cmp(3) [01000111] H12[11] rm[5..3] rd[2..0] */
+ ARMV5TE_EOR, /* eor [0100000001] rm[5..3] rd[2..0] */
+ ARMV5TE_LDMIA, /* ldmia [11001] rn[10..8] reglist [7..0] */
+ ARMV5TE_LDR_RRI5, /* ldr(1) [01101] imm_5[10..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDR_RRR, /* ldr(2) [0101100] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDR_PC_REL, /* ldr(3) [01001] rd[10..8] imm_8[7..0] */
+ ARMV5TE_LDR_SP_REL, /* ldr(4) [10011] rd[10..8] imm_8[7..0] */
+ ARMV5TE_LDRB_RRI5, /* ldrb(1) [01111] imm_5[10..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDRB_RRR, /* ldrb(2) [0101110] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDRH_RRI5, /* ldrh(1) [10001] imm_5[10..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDRH_RRR, /* ldrh(2) [0101101] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDRSB_RRR, /* ldrsb [0101011] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LDRSH_RRR, /* ldrsh [0101111] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_LSL, /* lsl(1) [00000] imm_5[10..6] rm[5..3] rd[2..0] */
+ ARMV5TE_LSLV, /* lsl(2) [0100000010] rs[5..3] rd[2..0] */
+ ARMV5TE_LSR, /* lsr(1) [00001] imm_5[10..6] rm[5..3] rd[2..0] */
+ ARMV5TE_LSRV, /* lsr(2) [0100000011] rs[5..3] rd[2..0] */
+ ARMV5TE_MOV_IMM, /* mov(1) [00100] rd[10..8] imm_8[7..0] */
+ ARMV5TE_MOV_RR, /* mov(2) [0001110000] rn[5..3] rd[2..0] */
+ ARMV5TE_MOV_RR_HL, /* mov(3) [01000110] H12[10] rm[5..3] rd[2..0] */
+ ARMV5TE_MOV_RR_LH, /* mov(3) [01000101] H12[01] rm[5..3] rd[2..0] */
+ ARMV5TE_MOV_RR_HH, /* mov(3) [01000111] H12[11] rm[5..3] rd[2..0] */
+ ARMV5TE_MUL, /* mul [0100001101] rm[5..3] rd[2..0] */
+ ARMV5TE_MVN, /* mvn [0100001111] rm[5..3] rd[2..0] */
+ ARMV5TE_NEG, /* neg [0100001001] rm[5..3] rd[2..0] */
+ ARMV5TE_ORR, /* orr [0100001100] rm[5..3] rd[2..0] */
+ ARMV5TE_POP, /* pop [1011110] r[8..8] rl[7..0] */
+ ARMV5TE_PUSH, /* push [1011010] r[8..8] rl[7..0] */
+ ARMV5TE_ROR, /* ror [0100000111] rs[5..3] rd[2..0] */
+ ARMV5TE_SBC, /* sbc [0100000110] rm[5..3] rd[2..0] */
+ ARMV5TE_STMIA, /* stmia [11000] rn[10..8] reglist [7.. 0] */
+ ARMV5TE_STR_RRI5, /* str(1) [01100] imm_5[10..6] rn[5..3] rd[2..0] */
+ ARMV5TE_STR_RRR, /* str(2) [0101000] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_STR_SP_REL, /* str(3) [10010] rd[10..8] imm_8[7..0] */
+ ARMV5TE_STRB_RRI5, /* strb(1) [01110] imm_5[10..6] rn[5..3] rd[2..0] */
+ ARMV5TE_STRB_RRR, /* strb(2) [0101010] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_STRH_RRI5, /* strh(1) [10000] imm_5[10..6] rn[5..3] rd[2..0] */
+ ARMV5TE_STRH_RRR, /* strh(2) [0101001] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_SUB_RRI3, /* sub(1) [0001111] imm_3[8..6] rn[5..3] rd[2..0]*/
+ ARMV5TE_SUB_RI8, /* sub(2) [00111] rd[10..8] imm_8[7..0] */
+ ARMV5TE_SUB_RRR, /* sub(3) [0001101] rm[8..6] rn[5..3] rd[2..0] */
+ ARMV5TE_SUB_SPI7, /* sub(4) [101100001] imm_7[6..0] */
+ ARMV5TE_SWI, /* swi [11011111] imm_8[7..0] */
+ ARMV5TE_TST, /* tst [0100001000] rm[5..3] rn[2..0] */
+ ARMV5TE_LAST,
+} Armv5teOpCode;
+
+/* Bit flags describing the behavior of each native opcode */
+typedef enum Armv5teOpFeatureFlags {
+ IS_BRANCH = 1 << 1,
+ CLOBBER_DEST = 1 << 2,
+ CLOBBER_SRC1 = 1 << 3,
+ NO_OPERAND = 1 << 4,
+ IS_UNARY_OP = 1 << 5,
+ IS_BINARY_OP = 1 << 6,
+ IS_TERTIARY_OP = 1 << 7,
+} Armv5teOpFeatureFlags;
+
+/* Struct used to define the snippet positions for each Thumb opcode */
+typedef struct Armv5teEncodingMap {
+ short skeleton;
+ struct {
+ int end;
+ int start;
+ } fieldLoc[3];
+ Armv5teOpCode opCode;
+ int flags;
+ char *name;
+ char* fmt;
+} Armv5teEncodingMap;
+
+extern Armv5teEncodingMap EncodingMap[ARMV5TE_LAST];
+
+/*
+ * Each instance of this struct holds a pseudo or real LIR instruction:
+ * - pesudo ones (eg labels and marks) and will be discarded by the assembler.
+ * - real ones will e assembled into Thumb instructions.
+ */
+typedef struct Armv5teLIR {
+ LIR generic;
+ Armv5teOpCode opCode;
+ int operands[3]; // [0..2] = [dest, src1, src2]
+ bool isNop; // LIR is optimized away
+ int age; // default is 0, set lazily by the optimizer
+} Armv5teLIR;
+
+/* Utility macros to traverse the LIR/Armv5teLIR list */
+#define NEXT_LIR(lir) ((Armv5teLIR *) lir->generic.next)
+#define PREV_LIR(lir) ((Armv5teLIR *) lir->generic.prev)
+
+#define NEXT_LIR_LVALUE(lir) (lir)->generic.next
+#define PREV_LIR_LVALUE(lir) (lir)->generic.prev
+
+#define CHAIN_CELL_OFFSET_TAG 0xcdab
+
+/* Create the TemplateOpcode enum */
+#define JIT_TEMPLATE(X) TEMPLATE_##X,
+typedef enum {
+#include "../../template/armv5te/TemplateOpList.h"
+/*
+ * For example,
+ * TEMPLATE_CMP_LONG,
+ * TEMPLATE_RETURN,
+ * ...
+ */
+ TEMPLATE_LAST_MARK,
+} TemplateOpCode;
+#undef JIT_TEMPLATE
+
+#endif /* _DALVIK_VM_COMPILER_CODEGEN_ARMV5TE_H */
diff --git a/vm/compiler/codegen/armv5te/Assemble.c b/vm/compiler/codegen/armv5te/Assemble.c
new file mode 100644
index 0000000..9b4595d
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/Assemble.c
@@ -0,0 +1,680 @@
+/*
+ * 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 "Dalvik.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+
+#include "../../CompilerInternals.h"
+#include "Armv5teLIR.h"
+#include <unistd.h> /* for cacheflush */
+
+/*
+ * opcode: Armv5teOpCode enum
+ * skeleton: pre-designated bit-pattern for this opcode
+ * ds: dest start bit position
+ * de: dest end bit position
+ * s1s: src1 start bit position
+ * s1e: src1 end bit position
+ * s2s: src2 start bit position
+ * s2e: src2 end bit position
+ * operands: number of operands (for sanity check purposes)
+ * name: mnemonic name
+ * fmt: for pretty-prining
+ */
+#define ENCODING_MAP(opcode, skeleton, ds, de, s1s, s1e, s2s, s2e, operands, \
+ name, fmt) \
+ {skeleton, {{ds, de}, {s1s, s1e}, {s2s, s2e}}, opcode, operands, name, \
+ fmt}
+
+/* Instruction dump string format keys: !pf, where "!" is the start
+ * of the key, "p" is which numeric operand to use and "f" is the
+ * print format.
+ *
+ * [p]ositions:
+ * 0 -> operands[0] (dest)
+ * 1 -> operands[1] (src1)
+ * 2 -> operands[2] (src2)
+ *
+ * [f]ormats:
+ * h -> 4-digit hex
+ * d -> decimal
+ * D -> decimal+8 (used to convert 3-bit regnum field to high reg)
+ * E -> decimal*4
+ * F -> decimal*2
+ * c -> branch condition (beq, bne, etc.)
+ * t -> pc-relative target
+ * u -> 1st half of bl[x] target
+ * v -> 2nd half ob bl[x] target
+ * R -> register list
+ *
+ * [!] escape. To insert "!", use "!!"
+ */
+/* NOTE: must be kept in sync with enum Armv5teOpcode from Armv5teLIR.h */
+Armv5teEncodingMap EncodingMap[ARMV5TE_LAST] = {
+ ENCODING_MAP(ARMV5TE_16BIT_DATA, 0x0000, 15, 0, -1, -1, -1, -1,
+ IS_UNARY_OP,
+ "data", "0x!0h(!0d)"),
+ ENCODING_MAP(ARMV5TE_ADC, 0x4140, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "adc", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_ADD_RRI3, 0x1c00, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "add", "r!0d, r!1d, #!2d"),
+ ENCODING_MAP(ARMV5TE_ADD_RI8, 0x3000, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "add", "r!0d, r!0d, #!1d"),
+ ENCODING_MAP(ARMV5TE_ADD_RRR, 0x1800, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "add", "r!0d, r!1d, r!2d"),
+ ENCODING_MAP(ARMV5TE_ADD_RR_LH, 0x4440, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "add",
+ "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_ADD_RR_HL, 0x4480, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "add", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_ADD_RR_HH, 0x44c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "add", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_ADD_PC_REL, 0xa000, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "add", "r!0d, pc, #!1E"),
+ ENCODING_MAP(ARMV5TE_ADD_SP_REL, 0xa800, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "add", "r!0d, sp, #!1E"),
+ ENCODING_MAP(ARMV5TE_ADD_SPI7, 0xb000, 6, 0, -1, -1, -1, -1,
+ IS_UNARY_OP | CLOBBER_DEST,
+ "add", "sp, #!0d*4"),
+ ENCODING_MAP(ARMV5TE_AND_RR, 0x4000, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "and", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_ASR, 0x1000, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "asr", "r!0d, r!1d, #!2d"),
+ ENCODING_MAP(ARMV5TE_ASRV, 0x4100, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "asr", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_B_COND, 0xd000, 7, 0, 11, 8, -1, -1,
+ IS_BINARY_OP | IS_BRANCH,
+ "!1c", "!0t"),
+ ENCODING_MAP(ARMV5TE_B_UNCOND, 0xe000, 10, 0, -1, -1, -1, -1,
+ NO_OPERAND | IS_BRANCH,
+ "b", "!0t"),
+ ENCODING_MAP(ARMV5TE_BIC, 0x4380, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "bic", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_BKPT, 0xbe00, 7, 0, -1, -1, -1, -1,
+ IS_UNARY_OP | IS_BRANCH,
+ "bkpt", "!0d"),
+ ENCODING_MAP(ARMV5TE_BLX_1, 0xf000, 10, 0, -1, -1, -1, -1,
+ IS_BINARY_OP | IS_BRANCH,
+ "blx_1", "!0u"),
+ ENCODING_MAP(ARMV5TE_BLX_2, 0xe800, 10, 0, -1, -1, -1, -1,
+ IS_BINARY_OP | IS_BRANCH,
+ "blx_2", "!0v"),
+ ENCODING_MAP(ARMV5TE_BL_1, 0xf000, 10, 0, -1, -1, -1, -1,
+ IS_UNARY_OP | IS_BRANCH,
+ "bl_1", "!0u"),
+ ENCODING_MAP(ARMV5TE_BL_2, 0xf800, 10, 0, -1, -1, -1, -1,
+ IS_UNARY_OP | IS_BRANCH,
+ "bl_2", "!0v"),
+ ENCODING_MAP(ARMV5TE_BLX_R, 0x4780, 6, 3, -1, -1, -1, -1,
+ IS_UNARY_OP | IS_BRANCH,
+ "blx", "r!0d"),
+ ENCODING_MAP(ARMV5TE_BX, 0x4700, 6, 3, -1, -1, -1, -1,
+ IS_UNARY_OP | IS_BRANCH,
+ "bx", "r!0d"),
+ ENCODING_MAP(ARMV5TE_CMN, 0x42c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP,
+ "cmn", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_CMP_RI8, 0x2800, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP,
+ "cmp", "r!0d, #!1d"),
+ ENCODING_MAP(ARMV5TE_CMP_RR, 0x4280, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP,
+ "cmp", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_CMP_LH, 0x4540, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP,
+ "cmp", "r!0d, r!1D"),
+ ENCODING_MAP(ARMV5TE_CMP_HL, 0x4580, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP,
+ "cmp", "r!0D, r!1d"),
+ ENCODING_MAP(ARMV5TE_CMP_HH, 0x45c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP,
+ "cmp", "r!0D, r!1D"),
+ ENCODING_MAP(ARMV5TE_EOR, 0x4040, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "eor", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_LDMIA, 0xc800, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST | CLOBBER_SRC1,
+ "ldmia", "r!0d!!, <!1R>"),
+ ENCODING_MAP(ARMV5TE_LDR_RRI5, 0x6800, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldr", "r!0d, [r!1d, #!2E]"),
+ ENCODING_MAP(ARMV5TE_LDR_RRR, 0x5800, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldr", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_LDR_PC_REL, 0x4800, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "ldr", "r!0d, [pc, #!1E]"),
+ ENCODING_MAP(ARMV5TE_LDR_SP_REL, 0x9800, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "ldr", "r!0d, [sp, #!1E]"),
+ ENCODING_MAP(ARMV5TE_LDRB_RRI5, 0x7800, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldrb", "r!0d, [r!1d, #2d]"),
+ ENCODING_MAP(ARMV5TE_LDRB_RRR, 0x5c00, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldrb", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_LDRH_RRI5, 0x8800, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldrh", "r!0d, [r!1d, #!2F]"),
+ ENCODING_MAP(ARMV5TE_LDRH_RRR, 0x5a00, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldrh", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_LDRSB_RRR, 0x5600, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldrsb", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_LDRSH_RRR, 0x5e00, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "ldrsh", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_LSL, 0x0000, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "lsl", "r!0d, r!1d, #!2d"),
+ ENCODING_MAP(ARMV5TE_LSLV, 0x4080, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "lsl", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_LSR, 0x0800, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "lsr", "r!0d, r!1d, #!2d"),
+ ENCODING_MAP(ARMV5TE_LSRV, 0x40c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "lsr", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_MOV_IMM, 0x2000, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mov", "r!0d, #!1d"),
+ ENCODING_MAP(ARMV5TE_MOV_RR, 0x1c00, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mov", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_MOV_RR_LH, 0x4640, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mov", "r!0D, r!1d"),
+ ENCODING_MAP(ARMV5TE_MOV_RR_HL, 0x4680, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mov", "r!0d, r!1D"),
+ ENCODING_MAP(ARMV5TE_MOV_RR_HH, 0x46c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mov", "r!0D, r!1D"),
+ ENCODING_MAP(ARMV5TE_MUL, 0x4340, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mul", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_MVN, 0x43c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "mvn", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_NEG, 0x4240, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "neg", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_ORR, 0x4300, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "orr", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_POP, 0xbc00, 8, 0, -1, -1, -1, -1,
+ IS_UNARY_OP,
+ "pop", "<!0R>"),
+ ENCODING_MAP(ARMV5TE_PUSH, 0xb400, 8, 0, -1, -1, -1, -1,
+ IS_UNARY_OP,
+ "push", "<!0R>"),
+ ENCODING_MAP(ARMV5TE_ROR, 0x41c0, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "ror", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_SBC, 0x4180, 2, 0, 5, 3, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "sbc", "r!0d, r!1d"),
+ ENCODING_MAP(ARMV5TE_STMIA, 0xc000, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_SRC1,
+ "stmia", "r!0d!!, <!1R>"),
+ ENCODING_MAP(ARMV5TE_STR_RRI5, 0x6000, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP,
+ "str", "r!0d, [r!1d, #!2E]"),
+ ENCODING_MAP(ARMV5TE_STR_RRR, 0x5000, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP,
+ "str", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_STR_SP_REL, 0x9000, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP,
+ "str", "r!0d, [sp, #!1E]"),
+ ENCODING_MAP(ARMV5TE_STRB_RRI5, 0x7000, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP,
+ "strb", "r!0d, [r!1d, #!2d]"),
+ ENCODING_MAP(ARMV5TE_STRB_RRR, 0x5400, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP,
+ "strb", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_STRH_RRI5, 0x8000, 2, 0, 5, 3, 10, 6,
+ IS_TERTIARY_OP,
+ "strh", "r!0d, [r!1d, #!2F]"),
+ ENCODING_MAP(ARMV5TE_STRH_RRR, 0x5200, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP,
+ "strh", "r!0d, [r!1d, r!2d]"),
+ ENCODING_MAP(ARMV5TE_SUB_RRI3, 0x1e00, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "sub", "r!0d, r!1d, #!2d]"),
+ ENCODING_MAP(ARMV5TE_SUB_RI8, 0x3800, 10, 8, 7, 0, -1, -1,
+ IS_BINARY_OP | CLOBBER_DEST,
+ "sub", "r!0d, #!1d"),
+ ENCODING_MAP(ARMV5TE_SUB_RRR, 0x1a00, 2, 0, 5, 3, 8, 6,
+ IS_TERTIARY_OP | CLOBBER_DEST,
+ "sub", "r!0d, r!1d, r!2d"),
+ ENCODING_MAP(ARMV5TE_SUB_SPI7, 0xb080, 6, 0, -1, -1, -1, -1,
+ IS_UNARY_OP | CLOBBER_DEST,
+ "sub", "sp, #!0d"),
+ ENCODING_MAP(ARMV5TE_SWI, 0xdf00, 7, 0, -1, -1, -1, -1,
+ IS_UNARY_OP | IS_BRANCH,
+ "swi", "!0d"),
+ ENCODING_MAP(ARMV5TE_TST, 0x4200, 2, 0, 5, 3, -1, -1,
+ IS_UNARY_OP,
+ "tst", "r!0d, r!1d"),
+};
+
+#define PADDING_MOV_R0_R0 0x1C00
+
+/* Write the numbers in the literal pool to the codegen stream */
+static void installDataContent(CompilationUnit *cUnit)
+{
+ int *dataPtr = (int *) (cUnit->baseAddr + cUnit->dataOffset);
+ Armv5teLIR *dataLIR = (Armv5teLIR *) cUnit->wordList;
+ while (dataLIR) {
+ *dataPtr++ = dataLIR->operands[0];
+ dataLIR = NEXT_LIR(dataLIR);
+ }
+}
+
+/* Returns the size of a Jit trace description */
+static int jitTraceDescriptionSize(const JitTraceDescription *desc)
+{
+ int runCount;
+ for (runCount = 0; ; runCount++) {
+ if (desc->trace[runCount].frag.runEnd)
+ break;
+ }
+ return sizeof(JitCodeDesc) + ((runCount+1) * sizeof(JitTraceRun));
+}
+
+/* Return TRUE if error happens */
+static bool assembleInstructions(CompilationUnit *cUnit, intptr_t startAddr)
+{
+ short *bufferAddr = (short *) cUnit->codeBuffer;
+ Armv5teLIR *lir;
+
+ for (lir = (Armv5teLIR *) cUnit->firstLIRInsn; lir; lir = NEXT_LIR(lir)) {
+ if (lir->opCode < 0) {
+ if ((lir->opCode == ARMV5TE_PSEUDO_ALIGN4) &&
+ /* 1 means padding is needed */
+ (lir->operands[0] == 1)) {
+ *bufferAddr++ = PADDING_MOV_R0_R0;
+ }
+ continue;
+ }
+
+ if (lir->isNop) {
+ continue;
+ }
+
+ if (lir->opCode == ARMV5TE_LDR_PC_REL ||
+ lir->opCode == ARMV5TE_ADD_PC_REL) {
+ Armv5teLIR *lirTarget = (Armv5teLIR *) lir->generic.target;
+ intptr_t pc = (lir->generic.offset + 4) & ~3;
+ intptr_t target = lirTarget->generic.offset;
+ int delta = target - pc;
+ if (delta & 0x3) {
+ LOGE("PC-rel distance is not multiples of 4: %d\n", delta);
+ dvmAbort();
+ }
+ if (delta > 1023) {
+ return true;
+ }
+ lir->operands[1] = delta >> 2;
+ } else if (lir->opCode == ARMV5TE_B_COND) {
+ Armv5teLIR *targetLIR = (Armv5teLIR *) lir->generic.target;
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ int delta = target - pc;
+ if (delta > 254 || delta < -256) {
+ return true;
+ }
+ lir->operands[0] = delta >> 1;
+ } else if (lir->opCode == ARMV5TE_B_UNCOND) {
+ Armv5teLIR *targetLIR = (Armv5teLIR *) lir->generic.target;
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ int delta = target - pc;
+ if (delta > 2046 || delta < -2048) {
+ LOGE("Unconditional branch distance out of range: %d\n", delta);
+ dvmAbort();
+ }
+ lir->operands[0] = delta >> 1;
+ } else if (lir->opCode == ARMV5TE_BLX_1) {
+ assert(NEXT_LIR(lir)->opCode == ARMV5TE_BLX_2);
+ /* curPC is Thumb */
+ intptr_t curPC = (startAddr + lir->generic.offset + 4) & ~3;
+ intptr_t target = lir->operands[1];
+
+ /* Match bit[1] in target with base */
+ if (curPC & 0x2) {
+ target |= 0x2;
+ }
+ int delta = target - curPC;
+ assert((delta >= -(1<<22)) && (delta <= ((1<<22)-2)));
+
+ lir->operands[0] = (delta >> 12) & 0x7ff;
+ NEXT_LIR(lir)->operands[0] = (delta>> 1) & 0x7ff;
+ }
+
+ Armv5teEncodingMap *encoder = &EncodingMap[lir->opCode];
+ short bits = encoder->skeleton;
+ int i;
+ for (i = 0; i < 3; i++) {
+ short value;
+ if (encoder->fieldLoc[i].end != -1) {
+ value = (lir->operands[i] << encoder->fieldLoc[i].start) &
+ ((1 << (encoder->fieldLoc[i].end + 1)) - 1);
+ bits |= value;
+
+ }
+ }
+ *bufferAddr++ = bits;
+ }
+ return false;
+}
+
+/*
+ * Translation layout in the code cache. Note that the codeAddress pointer
+ * in JitTable will point directly to the code body (field codeAddress). The
+ * chain cell offset codeAddress - 2, and (if present) executionCount is at
+ * codeAddress - 6.
+ *
+ * +----------------------------+
+ * | Execution count | -> [Optional] 4 bytes
+ * +----------------------------+
+ * +--| Offset to chain cell counts| -> 2 bytes
+ * | +----------------------------+
+ * | | Code body | -> Start address for translation
+ * | | | variable in 2-byte chunks
+ * | . . (JitTable's codeAddress points here)
+ * | . .
+ * | | |
+ * | +----------------------------+
+ * | | Chaining Cells | -> 8 bytes each, must be 4 byte aligned
+ * | . .
+ * | . .
+ * | | |
+ * | +----------------------------+
+ * +->| Chaining cell counts | -> 4 bytes, chain cell counts by type
+ * +----------------------------+
+ * | Trace description | -> variable sized
+ * . .
+ * | |
+ * +----------------------------+
+ * | Literal pool | -> 4-byte aligned, variable size
+ * . .
+ * . .
+ * | |
+ * +----------------------------+
+ *
+ * Go over each instruction in the list and calculate the offset from the top
+ * before sending them off to the assembler. If out-of-range branch distance is
+ * seen rearrange the instructions a bit to correct it.
+ */
+void dvmCompilerAssembleLIR(CompilationUnit *cUnit)
+{
+ LIR *lir;
+ Armv5teLIR *armLIR;
+ int offset = 0;
+ int i;
+ ChainCellCounts chainCellCounts;
+ int descSize = jitTraceDescriptionSize(cUnit->traceDesc);
+
+ /* Beginning offset needs to allow space for chain cell offset */
+ for (armLIR = (Armv5teLIR *) cUnit->firstLIRInsn;
+ armLIR;
+ armLIR = NEXT_LIR(armLIR)) {
+ armLIR->generic.offset = offset;
+ if (armLIR->opCode >= 0 && !armLIR->isNop) {
+ offset += 2;
+ } else if (armLIR->opCode == ARMV5TE_PSEUDO_ALIGN4) {
+ if (offset & 0x2) {
+ offset += 2;
+ armLIR->operands[0] = 1;
+ } else {
+ armLIR->operands[0] = 0;
+ }
+ }
+ /* Pseudo opcodes don't consume space */
+ }
+
+ /* Const values have to be word aligned */
+ offset = (offset + 3) & ~3;
+
+ /* Add space for chain cell counts & trace description */
+ u4 chainCellOffset = offset;
+ Armv5teLIR *chainCellOffsetLIR = cUnit->chainCellOffsetLIR;
+ assert(chainCellOffsetLIR);
+ assert(chainCellOffset < 0x10000);
+ assert(chainCellOffsetLIR->opCode == ARMV5TE_16BIT_DATA &&
+ chainCellOffsetLIR->operands[0] == CHAIN_CELL_OFFSET_TAG);
+
+ /* Replace the CHAIN_CELL_OFFSET_TAG with the real value */
+ chainCellOffsetLIR->operands[0] = chainCellOffset;
+
+ offset += sizeof(chainCellCounts) + descSize;
+
+ assert((offset & 0x3) == 0); /* Should still be word aligned */
+
+ /* Set up offsets for literals */
+ cUnit->dataOffset = offset;
+
+ for (lir = cUnit->wordList; lir; lir = lir->next) {
+ lir->offset = offset;
+ offset += 4;
+ }
+
+ cUnit->totalSize = offset;
+
+ if (gDvmJit.codeCacheByteUsed + cUnit->totalSize > CODE_CACHE_SIZE) {
+ gDvmJit.codeCacheFull = true;
+ cUnit->baseAddr = NULL;
+ return;
+ }
+
+ /* Allocate enough space for the code block */
+ cUnit->codeBuffer = dvmCompilerNew(chainCellOffset, true);
+ if (cUnit->codeBuffer == NULL) {
+ LOGE("Code buffer allocation failure\n");
+ cUnit->baseAddr = NULL;
+ return;
+ }
+
+ bool assemblerFailure = assembleInstructions(
+ cUnit, (intptr_t) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed);
+
+ /*
+ * Currently the only reason that can cause the assembler to fail is due to
+ * trace length - cut it in half and retry.
+ */
+ if (assemblerFailure) {
+ cUnit->halveInstCount = true;
+ return;
+ }
+
+
+ cUnit->baseAddr = (char *) gDvmJit.codeCache + gDvmJit.codeCacheByteUsed;
+ gDvmJit.codeCacheByteUsed += offset;
+
+ /* Install the code block */
+ memcpy((char*)cUnit->baseAddr, cUnit->codeBuffer, chainCellOffset);
+ gDvmJit.numCompilations++;
+
+ /* Install the chaining cell counts */
+ for (i=0; i< CHAINING_CELL_LAST; i++) {
+ chainCellCounts.u.count[i] = cUnit->numChainingCells[i];
+ }
+ memcpy((char*)cUnit->baseAddr + chainCellOffset, &chainCellCounts,
+ sizeof(chainCellCounts));
+
+ /* Install the trace description */
+ memcpy((char*)cUnit->baseAddr + chainCellOffset + sizeof(chainCellCounts),
+ cUnit->traceDesc, descSize);
+
+ /* Write the literals directly into the code cache */
+ installDataContent(cUnit);
+
+ /* Flush dcache and invalidate the icache to maintain coherence */
+ cacheflush((long)cUnit->baseAddr,
+ (long)(cUnit->baseAddr + offset), 0);
+}
+
+/*
+ * Perform translation chain operation.
+ * For ARM, we'll use a pair of thumb instructions to generate
+ * an unconditional chaining branch of up to 4MB in distance.
+ * Use a BL, though we don't really need the link. The format is
+ * 111HHooooooooooo
+ * Where HH is 10 for the 1st inst, and 11 for the second and
+ * the "o" field is each instruction's 11-bit contribution to the
+ * 22-bit branch offset.
+ * If the target is nearby, use a single-instruction bl.
+ * If one or more threads is suspended, don't chain.
+ */
+void* dvmJitChain(void* tgtAddr, u4* branchAddr)
+{
+ int baseAddr = (u4) branchAddr + 4;
+ int branchOffset = (int) tgtAddr - baseAddr;
+ u4 thumb1;
+ u4 thumb2;
+ u4 newInst;
+
+ if (gDvm.sumThreadSuspendCount == 0) {
+ assert((branchOffset >= -(1<<22)) && (branchOffset <= ((1<<22)-2)));
+
+ gDvmJit.translationChains++;
+
+ COMPILER_TRACE_CHAINING(
+ LOGD("Jit Runtime: chaining 0x%x to 0x%x\n",
+ (int) branchAddr, (int) tgtAddr & -2));
+ if ((branchOffset < -2048) | (branchOffset > 2046)) {
+ thumb1 = (0xf000 | ((branchOffset>>12) & 0x7ff));
+ thumb2 = (0xf800 | ((branchOffset>> 1) & 0x7ff));
+ } else {
+ thumb1 = (0xe000 | ((branchOffset>> 1) & 0x7ff));
+ thumb2 = 0x4300; /* nop -> or r0, r0 */
+ }
+
+ newInst = thumb2<<16 | thumb1;
+ *branchAddr = newInst;
+ cacheflush((long)branchAddr, (long)branchAddr + 4, 0);
+ }
+
+ return tgtAddr;
+}
+
+/*
+ * Unchain a trace given the starting address of the translation
+ * in the code cache. Refer to the diagram in dvmCompilerAssembleLIR.
+ * Returns the address following the last cell unchained. Note that
+ * the incoming codeAddr is a thumb code address, and therefore has
+ * the low bit set.
+ */
+u4* dvmJitUnchain(void* codeAddr)
+{
+ u2* pChainCellOffset = (u2*)((char*)codeAddr - 3);
+ u2 chainCellOffset = *pChainCellOffset;
+ ChainCellCounts *pChainCellCounts =
+ (ChainCellCounts*)((char*)codeAddr + chainCellOffset -3);
+ int cellCount;
+ u4* pChainCells;
+ u4* pStart;
+ u4 thumb1;
+ u4 thumb2;
+ u4 newInst;
+ int i,j;
+
+ /* Get total count of chain cells */
+ for (i = 0, cellCount = 0; i < CHAINING_CELL_LAST; i++) {
+ cellCount += pChainCellCounts->u.count[i];
+ }
+
+ /* Locate the beginning of the chain cell region */
+ pStart = pChainCells = (u4*)((char*)pChainCellCounts - (cellCount * 8));
+
+ /* The cells are sorted in order - walk through them and reset */
+ for (i = 0; i < CHAINING_CELL_LAST; i++) {
+ for (j = 0; j < pChainCellCounts->u.count[i]; j++) {
+ int targetOffset;
+ switch(i) {
+ case CHAINING_CELL_NORMAL:
+ targetOffset = offsetof(InterpState,
+ jitToInterpEntries.dvmJitToInterpNormal);
+ break;
+ case CHAINING_CELL_HOT:
+ case CHAINING_CELL_INVOKE:
+ targetOffset = offsetof(InterpState,
+ jitToInterpEntries.dvmJitToTraceSelect);
+ break;
+ default:
+ dvmAbort();
+ }
+ /*
+ * Arm code sequence for a chaining cell is:
+ * ldr r0, rGLUE, #<word offset>
+ * blx r0
+ */
+ COMPILER_TRACE_CHAINING(
+ LOGD("Jit Runtime: unchaining 0x%x", (int)pChainCells));
+ 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 += 2; /* Advance by 2 words */
+ }
+ }
+ return pChainCells;
+}
+
+/* Unchain all translation in the cache. */
+void dvmJitUnchainAll()
+{
+ u4* lowAddress = NULL;
+ u4* highAddress = NULL;
+ unsigned int i;
+ if (gDvmJit.pJitEntryTable != NULL) {
+ COMPILER_TRACE_CHAINING(LOGD("Jit Runtime: unchaining all"));
+ dvmLockMutex(&gDvmJit.tableLock);
+ for (i = 0; i < gDvmJit.jitTableSize; i++) {
+ if (gDvmJit.pJitEntryTable[i].dPC &&
+ gDvmJit.pJitEntryTable[i].codeAddress) {
+ u4* lastAddress;
+ lastAddress =
+ dvmJitUnchain(gDvmJit.pJitEntryTable[i].codeAddress);
+ if (lowAddress == NULL ||
+ (u4*)gDvmJit.pJitEntryTable[i].codeAddress < lowAddress)
+ lowAddress = lastAddress;
+ if (lastAddress > highAddress)
+ highAddress = lastAddress;
+ }
+ }
+ cacheflush((long)lowAddress, (long)highAddress, 0);
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ }
+}
diff --git a/vm/compiler/codegen/armv5te/Codegen.c b/vm/compiler/codegen/armv5te/Codegen.c
new file mode 100644
index 0000000..10589e1
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/Codegen.c
@@ -0,0 +1,3271 @@
+/*
+ * 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 "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "libdex/OpCode.h"
+#include "dexdump/OpCodeNames.h"
+#include "vm/compiler/CompilerInternals.h"
+#include "FpCodegen.h"
+#include "Armv5teLIR.h"
+#include "vm/mterp/common/FindInterface.h"
+
+/* Array holding the entry offset of each template relative to the first one */
+static intptr_t templateEntryOffsets[TEMPLATE_LAST_MARK];
+
+/* Track exercised opcodes */
+static int opcodeCoverage[256];
+
+/* non-existent register */
+#define vNone (-1)
+
+/* get the next register in r0..r3 in a round-robin fashion */
+#define NEXT_REG(reg) ((reg + 1) & 3)
+
+/*****************************************************************************/
+
+/*
+ * The following are building blocks to construct low-level IRs with 0 - 3
+ * operands.
+ */
+static Armv5teLIR *newLIR0(CompilationUnit *cUnit, Armv5teOpCode opCode)
+{
+ Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & NO_OPERAND));
+ insn->opCode = opCode;
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static Armv5teLIR *newLIR1(CompilationUnit *cUnit, Armv5teOpCode opCode,
+ int dest)
+{
+ Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ assert(isPseudoOpCode(opCode) || (EncodingMap[opCode].flags & IS_UNARY_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static Armv5teLIR *newLIR2(CompilationUnit *cUnit, Armv5teOpCode opCode,
+ int dest, int src1)
+{
+ Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ assert(isPseudoOpCode(opCode) ||
+ (EncodingMap[opCode].flags & IS_BINARY_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static Armv5teLIR *newLIR3(CompilationUnit *cUnit, Armv5teOpCode opCode,
+ int dest, int src1, int src2)
+{
+ Armv5teLIR *insn = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ assert(isPseudoOpCode(opCode) ||
+ (EncodingMap[opCode].flags & IS_TERTIARY_OP));
+ insn->opCode = opCode;
+ insn->operands[0] = dest;
+ insn->operands[1] = src1;
+ insn->operands[2] = src2;
+ dvmCompilerAppendLIR(cUnit, (LIR *) insn);
+ return insn;
+}
+
+static Armv5teLIR *newLIR23(CompilationUnit *cUnit, Armv5teOpCode opCode,
+ int srcdest, int src2)
+{
+ assert(!isPseudoOpCode(opCode));
+ if (EncodingMap[opCode].flags & IS_BINARY_OP)
+ return newLIR2(cUnit, opCode, srcdest, src2);
+ else
+ return newLIR3(cUnit, opCode, srcdest, srcdest, src2);
+}
+
+/*****************************************************************************/
+
+/*
+ * The following are utility routines to help maintain the RegisterScoreboard
+ * state to facilitate register renaming.
+ */
+
+/* Reset the tracker to unknown state */
+static inline void resetRegisterScoreboard(CompilationUnit *cUnit)
+{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+
+ dvmClearAllBits(registerScoreboard->nullCheckedRegs);
+ registerScoreboard->liveDalvikReg = vNone;
+ registerScoreboard->nativeReg = vNone;
+ registerScoreboard->nativeRegHi = vNone;
+}
+
+/* Kill the corresponding bit in the null-checked register list */
+static inline void killNullCheckedRegister(CompilationUnit *cUnit, int vReg)
+{
+ dvmClearBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
+}
+
+/* The Dalvik register pair held in native registers have changed */
+static inline void updateLiveRegisterPair(CompilationUnit *cUnit,
+ int vReg, int mRegLo, int mRegHi)
+{
+ cUnit->registerScoreboard.liveDalvikReg = vReg;
+ cUnit->registerScoreboard.nativeReg = mRegLo;
+ cUnit->registerScoreboard.nativeRegHi = mRegHi;
+ cUnit->registerScoreboard.isWide = true;
+}
+
+/* The Dalvik register held in a native register has changed */
+static inline void updateLiveRegister(CompilationUnit *cUnit,
+ int vReg, int mReg)
+{
+ cUnit->registerScoreboard.liveDalvikReg = vReg;
+ cUnit->registerScoreboard.nativeReg = mReg;
+ cUnit->registerScoreboard.isWide = false;
+}
+
+/*
+ * Given a Dalvik register id vSrc, use a very simple algorithm to increase
+ * the lifetime of cached Dalvik value in a native register.
+ */
+static inline int selectFirstRegister(CompilationUnit *cUnit, int vSrc,
+ bool isWide)
+{
+ RegisterScoreboard *registerScoreboard = &cUnit->registerScoreboard;
+
+ /* No live value - suggest to use r0 */
+ if (registerScoreboard->liveDalvikReg == vNone)
+ return r0;
+
+ /* Reuse the previously used native reg */
+ if (registerScoreboard->liveDalvikReg == vSrc) {
+ if (isWide != true) {
+ return registerScoreboard->nativeReg;
+ } else {
+ /* Return either r0 or r2 */
+ return (registerScoreboard->nativeReg + 1) & 2;
+ }
+ }
+
+ /* No reuse - choose the next one among r0..r3 in the round-robin fashion */
+ if (isWide) {
+ return (registerScoreboard->nativeReg + 2) & 2;
+ } else {
+ return (registerScoreboard->nativeReg + 1) & 3;
+ }
+
+}
+/*****************************************************************************/
+
+/*
+ * The following are building blocks to insert constants into the pool or
+ * instruction streams.
+ */
+
+/* Add a 32-bit constant either in the constant pool or mixed with code */
+static Armv5teLIR *addWordData(CompilationUnit *cUnit, int value, bool inPlace)
+{
+ /* Add the constant to the literal pool */
+ if (!inPlace) {
+ Armv5teLIR *newValue = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ newValue->operands[0] = value;
+ newValue->generic.next = cUnit->wordList;
+ cUnit->wordList = (LIR *) newValue;
+ return newValue;
+ } else {
+ /* Add the constant in the middle of code stream */
+ newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value & 0xffff));
+ newLIR1(cUnit, ARMV5TE_16BIT_DATA, (value >> 16));
+ }
+ return NULL;
+}
+
+/*
+ * Search the existing constants in the literal pool for an exact or close match
+ * within specified delta (greater or equal to 0).
+ */
+static Armv5teLIR *scanLiteralPool(CompilationUnit *cUnit, int value,
+ unsigned int delta)
+{
+ LIR *dataTarget = cUnit->wordList;
+ while (dataTarget) {
+ if (((unsigned) (value - ((Armv5teLIR *) dataTarget)->operands[0])) <=
+ delta)
+ return (Armv5teLIR *) dataTarget;
+ dataTarget = dataTarget->next;
+ }
+ return NULL;
+}
+
+/*
+ * Load a immediate using a shortcut if possible; otherwise
+ * grab from the per-translation literal pool
+ */
+void loadConstant(CompilationUnit *cUnit, int rDest, int value)
+{
+ /* See if the value can be constructed cheaply */
+ if ((value >= 0) && (value <= 255)) {
+ newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, value);
+ return;
+ } else if ((value & 0xFFFFFF00) == 0xFFFFFF00) {
+ newLIR2(cUnit, ARMV5TE_MOV_IMM, rDest, ~value);
+ newLIR2(cUnit, ARMV5TE_MVN, rDest, rDest);
+ return;
+ }
+ /* No shortcut - go ahead and use literal pool */
+ Armv5teLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+ if (dataTarget == NULL) {
+ dataTarget = addWordData(cUnit, value, false);
+ }
+ Armv5teLIR *loadPcRel = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ loadPcRel->opCode = ARMV5TE_LDR_PC_REL;
+ loadPcRel->generic.target = (LIR *) dataTarget;
+ loadPcRel->operands[0] = rDest;
+ dvmCompilerAppendLIR(cUnit, (LIR *) loadPcRel);
+
+ /*
+ * To save space in the constant pool, we use the ADD_RRI8 instruction to
+ * add up to 255 to an existing constant value.
+ */
+ if (dataTarget->operands[0] != value) {
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, value - dataTarget->operands[0]);
+ }
+}
+
+/* Export the Dalvik PC assicated with an instruction to the StackSave area */
+static void genExportPC(CompilationUnit *cUnit, MIR *mir, int rDPC, int rAddr)
+{
+ int offset = offsetof(StackSaveArea, xtra.currentPc);
+ loadConstant(cUnit, rDPC, (int) (cUnit->method->insns + mir->offset));
+ newLIR2(cUnit, ARMV5TE_MOV_RR, rAddr, rFP);
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, rAddr, sizeof(StackSaveArea) - offset);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, rDPC, rAddr, 0);
+}
+
+/* Generate conditional branch instructions */
+static void genConditionalBranch(CompilationUnit *cUnit,
+ Armv5teConditionCode cond,
+ Armv5teLIR *target)
+{
+ Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
+ branch->generic.target = (LIR *) target;
+}
+
+/* Generate unconditional branch instructions */
+static void genUnconditionalBranch(CompilationUnit *cUnit, Armv5teLIR *target)
+{
+ Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
+ branch->generic.target = (LIR *) target;
+}
+
+#define USE_IN_CACHE_HANDLER 1
+
+/*
+ * Jump to the out-of-line handler in ARM mode to finish executing the
+ * remaining of more complex instructions.
+ */
+static void genDispatchToHandler(CompilationUnit *cUnit, TemplateOpCode opCode)
+{
+#if USE_IN_CACHE_HANDLER
+ /*
+ * NOTE - In practice BLX only needs one operand, but since the assembler
+ * may abort itself and retry due to other out-of-range conditions we
+ * cannot really use operand[0] to store the absolute target address since
+ * it may get clobbered by the final relative offset. Therefore,
+ * we fake BLX_1 is a two operand instruction and the absolute target
+ * address is stored in operand[1].
+ */
+ newLIR2(cUnit, ARMV5TE_BLX_1,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
+ newLIR2(cUnit, ARMV5TE_BLX_2,
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode],
+ (int) gDvmJit.codeCache + templateEntryOffsets[opCode]);
+#else
+ /*
+ * In case we want to access the statically compiled handlers for
+ * debugging purposes, define USE_IN_CACHE_HANDLER to 0
+ */
+ void *templatePtr;
+
+#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
+#include "../../template/armv5te/TemplateOpList.h"
+#undef JIT_TEMPLATE
+ switch (opCode) {
+#define JIT_TEMPLATE(X) \
+ case TEMPLATE_##X: { templatePtr = dvmCompiler_TEMPLATE_##X; break; }
+#include "../../template/armv5te/TemplateOpList.h"
+#undef JIT_TEMPLATE
+ default: templatePtr = NULL;
+ }
+ loadConstant(cUnit, r7, (int) templatePtr);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r7);
+#endif
+}
+
+/* Perform the actual operation for OP_RETURN_* */
+static void genReturnCommon(CompilationUnit *cUnit, MIR *mir)
+{
+ genDispatchToHandler(cUnit, TEMPLATE_RETURN);
+#if defined(INVOKE_STATS)
+ gDvmJit.jitReturn++;
+#endif
+ int dPC = (int) (cUnit->method->insns + mir->offset);
+ Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ Armv5teLIR *pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = mir->offset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
+ /* Branch to the PC reconstruction code */
+ branch->generic.target = (LIR *) pcrLabel;
+}
+
+/*
+ * Load a pair of values of rFP[src..src+1] and store them into rDestLo and
+ * rDestHi
+ */
+static void loadValuePair(CompilationUnit *cUnit, int vSrc, int rDestLo,
+ int rDestHi)
+{
+ /* Use reg + imm5*4 to load the values if possible */
+ if (vSrc <= 30) {
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestLo, rFP, vSrc);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDestHi, rFP, vSrc+1);
+ } else {
+ if (vSrc <= 64) {
+ /* Sneak 4 into the base address first */
+ newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDestLo, rFP, 4);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, rDestHi, (vSrc-1)*4);
+ } else {
+ /* Offset too far from rFP */
+ loadConstant(cUnit, rDestLo, vSrc*4);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, rDestLo, rFP, rDestLo);
+ }
+ assert(rDestLo < rDestHi);
+ newLIR2(cUnit, ARMV5TE_LDMIA, rDestLo, (1<<rDestLo) | (1<<(rDestHi)));
+ }
+}
+
+/*
+ * Store a pair of values of rSrc and rSrc+1 and store them into vDest and
+ * vDest+1
+ */
+static void storeValuePair(CompilationUnit *cUnit, int rSrcLo, int rSrcHi,
+ int vDest, int rScratch)
+{
+ killNullCheckedRegister(cUnit, vDest);
+ killNullCheckedRegister(cUnit, vDest+1);
+ updateLiveRegisterPair(cUnit, vDest, rSrcLo, rSrcHi);
+
+ /* Use reg + imm5*4 to store the values if possible */
+ if (vDest <= 30) {
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcLo, rFP, vDest);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrcHi, rFP, vDest+1);
+ } else {
+ if (vDest <= 64) {
+ /* Sneak 4 into the base address first */
+ newLIR3(cUnit, ARMV5TE_ADD_RRI3, rScratch, rFP, 4);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, rScratch, (vDest-1)*4);
+ } else {
+ /* Offset too far from rFP */
+ loadConstant(cUnit, rScratch, vDest*4);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, rScratch, rFP, rScratch);
+ }
+ assert(rSrcLo < rSrcHi);
+ newLIR2(cUnit, ARMV5TE_STMIA, rScratch, (1<<rSrcLo) | (1 << (rSrcHi)));
+ }
+}
+
+/* Load the address of a Dalvik register on the frame */
+static void loadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
+{
+ /* RRI3 can add up to 7 */
+ if (vSrc <= 1) {
+ newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, vSrc*4);
+ } else if (vSrc <= 64) {
+ /* Sneak 4 into the base address first */
+ newLIR3(cUnit, ARMV5TE_ADD_RRI3, rDest, rFP, 4);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, rDest, (vSrc-1)*4);
+ } else {
+ loadConstant(cUnit, rDest, vSrc*4);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, rDest, rFP, rDest);
+ }
+}
+
+/* Load a single value from rFP[src] and store them into rDest */
+static void loadValue(CompilationUnit *cUnit, int vSrc, int rDest)
+{
+ /* Use reg + imm5*4 to load the value if possible */
+ if (vSrc <= 31) {
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, rDest, rFP, vSrc);
+ } else {
+ loadConstant(cUnit, rDest, vSrc*4);
+ newLIR3(cUnit, ARMV5TE_LDR_RRR, rDest, rFP, rDest);
+ }
+}
+
+/* Store a value from rSrc to vDest */
+static void storeValue(CompilationUnit *cUnit, int rSrc, int vDest,
+ int rScratch)
+{
+ killNullCheckedRegister(cUnit, vDest);
+ updateLiveRegister(cUnit, vDest, rSrc);
+
+ /* Use reg + imm5*4 to store the value if possible */
+ if (vDest <= 31) {
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, rSrc, rFP, vDest);
+ } else {
+ loadConstant(cUnit, rScratch, vDest*4);
+ newLIR3(cUnit, ARMV5TE_STR_RRR, rSrc, rFP, rScratch);
+ }
+}
+
+/*
+ * Perform a binary operation on 64-bit operands and leave the results in the
+ * r0/r1 pair.
+ */
+static void genBinaryOpWide(CompilationUnit *cUnit, int vDest,
+ Armv5teOpCode preinst, Armv5teOpCode inst,
+ int reg0, int reg2)
+{
+ int reg1 = NEXT_REG(reg0);
+ int reg3 = NEXT_REG(reg2);
+ newLIR23(cUnit, preinst, reg0, reg2);
+ newLIR23(cUnit, inst, reg1, reg3);
+ storeValuePair(cUnit, reg0, reg1, vDest, reg2);
+}
+
+/* Perform a binary operation on 32-bit operands and leave the results in r0. */
+static void genBinaryOp(CompilationUnit *cUnit, int vDest, Armv5teOpCode inst,
+ int reg0, int reg1, int regDest)
+{
+ if (EncodingMap[inst].flags & IS_BINARY_OP) {
+ newLIR2(cUnit, inst, reg0, reg1);
+ storeValue(cUnit, reg0, vDest, reg1);
+ } else {
+ newLIR3(cUnit, inst, regDest, reg0, reg1);
+ storeValue(cUnit, regDest, vDest, reg1);
+ }
+}
+
+/* Create the PC reconstruction slot if not already done */
+static inline Armv5teLIR *genCheckCommon(CompilationUnit *cUnit, int dOffset,
+ Armv5teLIR *branch,
+ Armv5teLIR *pcrLabel)
+{
+ /* Set up the place holder to reconstruct this Dalvik PC */
+ if (pcrLabel == NULL) {
+ int dPC = (int) (cUnit->method->insns + dOffset);
+ pcrLabel = dvmCompilerNew(sizeof(Armv5teLIR), true);
+ pcrLabel->opCode = ARMV5TE_PSEUDO_PC_RECONSTRUCTION_CELL;
+ pcrLabel->operands[0] = dPC;
+ pcrLabel->operands[1] = dOffset;
+ /* Insert the place holder to the growable list */
+ dvmInsertGrowableList(&cUnit->pcReconstructionList, pcrLabel);
+ }
+ /* Branch to the PC reconstruction code */
+ branch->generic.target = (LIR *) pcrLabel;
+ return pcrLabel;
+}
+
+/*
+ * Perform a "reg cmp imm" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static inline Armv5teLIR *genRegImmCheck(CompilationUnit *cUnit,
+ Armv5teConditionCode cond, int reg,
+ int checkValue, int dOffset,
+ Armv5teLIR *pcrLabel)
+{
+ newLIR2(cUnit, ARMV5TE_CMP_RI8, reg, checkValue);
+ Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+}
+
+/*
+ * Perform a "reg cmp reg" operation and jump to the PCR region if condition
+ * satisfies.
+ */
+static inline Armv5teLIR *inertRegRegCheck(CompilationUnit *cUnit,
+ Armv5teConditionCode cond,
+ int reg1, int reg2, int dOffset,
+ Armv5teLIR *pcrLabel)
+{
+ newLIR2(cUnit, ARMV5TE_CMP_RR, reg1, reg2);
+ Armv5teLIR *branch = newLIR2(cUnit, ARMV5TE_B_COND, 0, cond);
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+}
+
+/*
+ * Perform null-check on a register. vReg is the Dalvik register being checked,
+ * and mReg is the machine register holding the actual value. If internal state
+ * indicates that vReg has been checked before the check request is ignored.
+ */
+static Armv5teLIR *genNullCheck(CompilationUnit *cUnit, int vReg, int mReg,
+ int dOffset, Armv5teLIR *pcrLabel)
+{
+ /* This particular Dalvik register has been null-checked */
+ if (dvmIsBitSet(cUnit->registerScoreboard.nullCheckedRegs, vReg)) {
+ return pcrLabel;
+ }
+ dvmSetBit(cUnit->registerScoreboard.nullCheckedRegs, vReg);
+ return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
+}
+
+/*
+ * Perform zero-check on a register. Similar to genNullCheck but the value being
+ * checked does not have a corresponding Dalvik register.
+ */
+static Armv5teLIR *genZeroCheck(CompilationUnit *cUnit, int mReg,
+ int dOffset, Armv5teLIR *pcrLabel)
+{
+ return genRegImmCheck(cUnit, ARM_COND_EQ, mReg, 0, dOffset, pcrLabel);
+}
+
+/* Perform bound check on two registers */
+static Armv5teLIR *genBoundsCheck(CompilationUnit *cUnit, int rIndex,
+ int rBound, int dOffset, Armv5teLIR *pcrLabel)
+{
+ return inertRegRegCheck(cUnit, ARM_COND_CS, rIndex, rBound, dOffset,
+ pcrLabel);
+}
+
+/* Generate a unconditional branch to go to the interpreter */
+static inline Armv5teLIR *genTrap(CompilationUnit *cUnit, int dOffset,
+ Armv5teLIR *pcrLabel)
+{
+ Armv5teLIR *branch = newLIR0(cUnit, ARMV5TE_B_UNCOND);
+ return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
+}
+
+/* Load a wide field from an object instance */
+static void genIGetWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int reg0, reg1, reg2, reg3;
+
+ /* Allocate reg0..reg3 into physical registers r0..r3 */
+
+ /* See if vB is in a native register. If so, reuse it. */
+ reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
+ /* Ping reg3 to the other register of the same pair containing reg2 */
+ reg3 = reg2 ^ 0x1;
+ /*
+ * Ping reg0 to the first register of the alternate register pair
+ */
+ reg0 = (reg2 + 2) & 0x2;
+ reg1 = NEXT_REG(reg0);
+
+ loadValue(cUnit, dInsn->vB, reg2);
+ loadConstant(cUnit, reg3, fieldOffset);
+ genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, reg2, reg2, reg3);
+ newLIR2(cUnit, ARMV5TE_LDMIA, reg2, (1<<reg0 | 1<<reg1));
+ storeValuePair(cUnit, reg0, reg1, dInsn->vA, reg3);
+}
+
+/* Store a wide field to an object instance */
+static void genIPutWide(CompilationUnit *cUnit, MIR *mir, int fieldOffset)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int reg0, reg1, reg2, reg3;
+
+ /* Allocate reg0..reg3 into physical registers r0..r3 */
+
+ /* See if vB is in a native register. If so, reuse it. */
+ reg2 = selectFirstRegister(cUnit, dInsn->vB, false);
+ /* Ping reg3 to the other register of the same pair containing reg2 */
+ reg3 = reg2 ^ 0x1;
+ /*
+ * Ping reg0 to the first register of the alternate register pair
+ */
+ reg0 = (reg2 + 2) & 0x2;
+ reg1 = NEXT_REG(reg0);
+
+
+ loadValue(cUnit, dInsn->vB, reg2);
+ loadValuePair(cUnit, dInsn->vA, reg0, reg1);
+ updateLiveRegisterPair(cUnit, dInsn->vA, reg0, reg1);
+ loadConstant(cUnit, reg3, fieldOffset);
+ genNullCheck(cUnit, dInsn->vB, reg2, mir->offset, NULL); /* null object? */
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, reg2, reg2, reg3);
+ newLIR2(cUnit, ARMV5TE_STMIA, reg2, (1<<reg0 | 1<<reg1));
+}
+
+/*
+ * Load a field from an object instance
+ *
+ * Inst should be one of:
+ * ARMV5TE_LDR_RRR
+ * ARMV5TE_LDRB_RRR
+ * ARMV5TE_LDRH_RRR
+ * ARMV5TE_LDRSB_RRR
+ * ARMV5TE_LDRSH_RRR
+ */
+static void genIGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
+ int fieldOffset)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int reg0, reg1;
+
+ reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
+ reg1 = NEXT_REG(reg0);
+ /* TUNING: write a utility routine to load via base + constant offset */
+ loadValue(cUnit, dInsn->vB, reg0);
+ loadConstant(cUnit, reg1, fieldOffset);
+ genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
+ newLIR3(cUnit, inst, reg0, reg0, reg1);
+ storeValue(cUnit, reg0, dInsn->vA, reg1);
+}
+
+/*
+ * Store a field to an object instance
+ *
+ * Inst should be one of:
+ * ARMV5TE_STR_RRR
+ * ARMV5TE_STRB_RRR
+ * ARMV5TE_STRH_RRR
+ */
+static void genIPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
+ int fieldOffset)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ int reg0, reg1, reg2;
+
+ reg0 = selectFirstRegister(cUnit, dInsn->vB, false);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+
+ /* TUNING: write a utility routine to load via base + constant offset */
+ loadValue(cUnit, dInsn->vB, reg0);
+ loadConstant(cUnit, reg1, fieldOffset);
+ loadValue(cUnit, dInsn->vA, reg2);
+ updateLiveRegister(cUnit, dInsn->vA, reg2);
+ genNullCheck(cUnit, dInsn->vB, reg0, mir->offset, NULL); /* null object? */
+ newLIR3(cUnit, inst, reg2, reg0, reg1);
+}
+
+
+/* TODO: This should probably be done as an out-of-line instruction handler. */
+
+/*
+ * Generate array load
+ *
+ * Inst should be one of:
+ * ARMV5TE_LDR_RRR
+ * ARMV5TE_LDRB_RRR
+ * ARMV5TE_LDRH_RRR
+ * ARMV5TE_LDRSB_RRR
+ * ARMV5TE_LDRSH_RRR
+ */
+static void genArrayGet(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
+ int vArray, int vIndex, int vDest, int scale)
+{
+ int lenOffset = offsetof(ArrayObject, length);
+ int dataOffset = offsetof(ArrayObject, contents);
+ int reg0, reg1, reg2, reg3;
+
+ reg0 = selectFirstRegister(cUnit, vArray, false);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ reg3 = NEXT_REG(reg2);
+
+ loadValue(cUnit, vArray, reg2);
+ loadValue(cUnit, vIndex, reg3);
+
+ /* null object? */
+ Armv5teLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
+ NULL);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
+ genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
+ if (scale) {
+ newLIR3(cUnit, ARMV5TE_LSL, reg3, reg3, scale);
+ }
+ if (scale==3) {
+ newLIR3(cUnit, inst, reg0, reg2, reg3);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, 4);
+ newLIR3(cUnit, inst, reg1, reg2, reg3);
+ storeValuePair(cUnit, reg0, reg1, vDest, reg3);
+ } else {
+ newLIR3(cUnit, inst, reg0, reg2, reg3);
+ storeValue(cUnit, reg0, vDest, reg3);
+ }
+}
+
+/* TODO: This should probably be done as an out-of-line instruction handler. */
+
+/*
+ * Generate array store
+ *
+ * Inst should be one of:
+ * ARMV5TE_STR_RRR
+ * ARMV5TE_STRB_RRR
+ * ARMV5TE_STRH_RRR
+ */
+static void genArrayPut(CompilationUnit *cUnit, MIR *mir, Armv5teOpCode inst,
+ int vArray, int vIndex, int vSrc, int scale)
+{
+ int lenOffset = offsetof(ArrayObject, length);
+ int dataOffset = offsetof(ArrayObject, contents);
+ int reg0, reg1, reg2, reg3;
+
+ reg0 = selectFirstRegister(cUnit, vArray, false);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ reg3 = NEXT_REG(reg2);
+
+ loadValue(cUnit, vArray, reg2);
+ loadValue(cUnit, vIndex, reg3);
+
+ /* null object? */
+ Armv5teLIR * pcrLabel = genNullCheck(cUnit, vArray, reg2, mir->offset,
+ NULL);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg2, lenOffset >> 2); /* Get len */
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, dataOffset); /* reg2 -> array data */
+ genBoundsCheck(cUnit, reg3, reg0, mir->offset, pcrLabel);
+ /* at this point, reg2 points to array, reg3 is unscaled index */
+ if (scale==3) {
+ loadValuePair(cUnit, vSrc, reg0, reg1);
+ updateLiveRegisterPair(cUnit, vSrc, reg0, reg1);
+ } else {
+ loadValue(cUnit, vSrc, reg0);
+ updateLiveRegister(cUnit, vSrc, reg0);
+ }
+ if (scale) {
+ newLIR3(cUnit, ARMV5TE_LSL, reg3, reg3, scale);
+ }
+ /*
+ * at this point, reg2 points to array, reg3 is scaled index, and
+ * reg0[reg1] is data
+ */
+ if (scale==3) {
+ newLIR3(cUnit, inst, reg0, reg2, reg3);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, reg2, 4);
+ newLIR3(cUnit, inst, reg1, reg2, reg3);
+ } else {
+ newLIR3(cUnit, inst, reg0, reg2, reg3);
+ }
+}
+
+static bool genShiftOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vShift)
+{
+ /*
+ * Don't mess with the regsiters here as there is a particular calling
+ * convention to the out-of-line handler.
+ */
+ loadValue(cUnit, vShift, r2);
+ loadValuePair(cUnit, vSrc1, r0, r1);
+ switch( mir->dalvikInsn.opCode) {
+ case OP_SHL_LONG:
+ case OP_SHL_LONG_2ADDR:
+ genDispatchToHandler(cUnit, TEMPLATE_SHL_LONG);
+ break;
+ case OP_SHR_LONG:
+ case OP_SHR_LONG_2ADDR:
+ genDispatchToHandler(cUnit, TEMPLATE_SHR_LONG);
+ break;
+ case OP_USHR_LONG:
+ case OP_USHR_LONG_2ADDR:
+ genDispatchToHandler(cUnit, TEMPLATE_USHR_LONG);
+ break;
+ default:
+ return true;
+ }
+ storeValuePair(cUnit, r0, r1, vDest, r2);
+ return false;
+}
+bool dvmCompilerGenArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ int vDest, int vSrc1, int vSrc2)
+{
+ /*
+ * Don't optimize the regsiter usage here as they are governed by the EABI
+ * calling convention.
+ */
+ void* funct;
+ int reg0, reg1;
+
+ /* TODO: use a proper include file to define these */
+ float __aeabi_fadd(float a, float b);
+ float __aeabi_fsub(float a, float b);
+ float __aeabi_fdiv(float a, float b);
+ float __aeabi_fmul(float a, float b);
+ float fmodf(float a, float b);
+
+ reg0 = selectFirstRegister(cUnit, vSrc2, false);
+ reg1 = NEXT_REG(reg0);
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ funct = (void*) __aeabi_fadd;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ funct = (void*) __aeabi_fsub;
+ break;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ funct = (void*) __aeabi_fdiv;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ funct = (void*) __aeabi_fmul;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ funct = (void*) fmodf;
+ break;
+ case OP_NEG_FLOAT: {
+ loadValue(cUnit, vSrc2, reg0);
+ loadConstant(cUnit, reg1, 0x80000000);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, reg0, reg0, reg1);
+ storeValue(cUnit, reg0, vDest, reg1);
+ return false;
+ }
+ default:
+ return true;
+ }
+ loadConstant(cUnit, r2, (int)funct);
+ loadValue(cUnit, vSrc1, r0);
+ loadValue(cUnit, vSrc2, r1);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ storeValue(cUnit, r0, vDest, r1);
+ return false;
+}
+
+bool dvmCompilerGenArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ int vDest, int vSrc1, int vSrc2)
+{
+ void* funct;
+ int reg0, reg1, reg2;
+
+ /* TODO: use a proper include file to define these */
+ double __aeabi_dadd(double a, double b);
+ double __aeabi_dsub(double a, double b);
+ double __aeabi_ddiv(double a, double b);
+ double __aeabi_dmul(double a, double b);
+ double fmod(double a, double b);
+
+ reg0 = selectFirstRegister(cUnit, vSrc2, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ funct = (void*) __aeabi_dadd;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ funct = (void*) __aeabi_dsub;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ funct = (void*) __aeabi_ddiv;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ funct = (void*) __aeabi_dmul;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ funct = (void*) fmod;
+ break;
+ case OP_NEG_DOUBLE: {
+ loadValuePair(cUnit, vSrc2, reg0, reg1);
+ loadConstant(cUnit, reg2, 0x80000000);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, reg1, reg1, reg2);
+ storeValuePair(cUnit, reg0, reg1, vDest, reg2);
+ return false;
+ }
+ default:
+ return true;
+ }
+ /*
+ * Don't optimize the regsiter usage here as they are governed by the EABI
+ * calling convention.
+ */
+ loadConstant(cUnit, r4PC, (int)funct);
+ loadValuePair(cUnit, vSrc1, r0, r1);
+ loadValuePair(cUnit, vSrc2, r2, r3);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ storeValuePair(cUnit, r0, r1, vDest, r2);
+ return false;
+}
+
+static bool genArithOpLong(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ int firstOp = ARMV5TE_BKPT;
+ int secondOp = ARMV5TE_BKPT;
+ bool callOut = false;
+ void *callTgt;
+ int retReg = r0;
+ int reg0, reg1, reg2, reg3;
+ /* TODO - find proper .h file to declare these */
+ long long __aeabi_ldivmod(long long op1, long long op2);
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_NOT_LONG:
+ firstOp = ARMV5TE_MVN;
+ secondOp = ARMV5TE_MVN;
+ break;
+ case OP_ADD_LONG:
+ case OP_ADD_LONG_2ADDR:
+ firstOp = ARMV5TE_ADD_RRR;
+ secondOp = ARMV5TE_ADC;
+ break;
+ case OP_SUB_LONG:
+ case OP_SUB_LONG_2ADDR:
+ firstOp = ARMV5TE_SUB_RRR;
+ secondOp = ARMV5TE_SBC;
+ break;
+ case OP_MUL_LONG:
+ case OP_MUL_LONG_2ADDR:
+ loadValuePair(cUnit, vSrc1, r0, r1);
+ loadValuePair(cUnit, vSrc2, r2, r3);
+ genDispatchToHandler(cUnit, TEMPLATE_MUL_LONG);
+ storeValuePair(cUnit, r0, r1, vDest, r2);
+ return false;
+ break;
+ case OP_DIV_LONG:
+ case OP_DIV_LONG_2ADDR:
+ callOut = true;
+ retReg = r0;
+ callTgt = (void*)__aeabi_ldivmod;
+ break;
+ /* NOTE - result is in r2/r3 instead of r0/r1 */
+ case OP_REM_LONG:
+ case OP_REM_LONG_2ADDR:
+ callOut = true;
+ callTgt = (void*)__aeabi_ldivmod;
+ retReg = r2;
+ break;
+ case OP_AND_LONG:
+ case OP_AND_LONG_2ADDR:
+ firstOp = ARMV5TE_AND_RR;
+ secondOp = ARMV5TE_AND_RR;
+ break;
+ case OP_OR_LONG:
+ case OP_OR_LONG_2ADDR:
+ firstOp = ARMV5TE_ORR;
+ secondOp = ARMV5TE_ORR;
+ break;
+ case OP_XOR_LONG:
+ case OP_XOR_LONG_2ADDR:
+ firstOp = ARMV5TE_EOR;
+ secondOp = ARMV5TE_EOR;
+ break;
+ case OP_NEG_LONG: {
+ reg0 = selectFirstRegister(cUnit, vSrc2, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ reg3 = NEXT_REG(reg2);
+
+ loadValuePair(cUnit, vSrc2, reg0, reg1);
+ loadConstant(cUnit, reg3, 0);
+ newLIR3(cUnit, ARMV5TE_SUB_RRR, reg2, reg3, reg0);
+ newLIR2(cUnit, ARMV5TE_SBC, reg3, reg1);
+ storeValuePair(cUnit, r0, reg3, vDest, reg0);
+ return false;
+ }
+ default:
+ LOGE("Invalid long arith op");
+ dvmAbort();
+ }
+ if (!callOut) {
+ reg0 = selectFirstRegister(cUnit, vSrc1, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ reg3 = NEXT_REG(reg2);
+
+ loadValuePair(cUnit, vSrc1, reg0, reg1);
+ loadValuePair(cUnit, vSrc2, reg2, reg3);
+ genBinaryOpWide(cUnit, vDest, firstOp, secondOp, reg0, reg2);
+ /*
+ * Don't optimize the regsiter usage here as they are governed by the EABI
+ * calling convention.
+ */
+ } else {
+ loadValuePair(cUnit, vSrc2, r2, r3);
+ loadConstant(cUnit, r4PC, (int) callTgt);
+ loadValuePair(cUnit, vSrc1, r0, r1);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ storeValuePair(cUnit, retReg, retReg+1, vDest, r4PC);
+ }
+ return false;
+}
+
+static bool genArithOpInt(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ int armOp = ARMV5TE_BKPT;
+ bool callOut = false;
+ bool checkZero = false;
+ int retReg = r0;
+ void *callTgt;
+ int reg0, reg1, regDest;
+
+ /* TODO - find proper .h file to declare these */
+ int __aeabi_idivmod(int op1, int op2);
+ int __aeabi_idiv(int op1, int op2);
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_NEG_INT:
+ armOp = ARMV5TE_NEG;
+ break;
+ case OP_NOT_INT:
+ armOp = ARMV5TE_MVN;
+ break;
+ case OP_ADD_INT:
+ case OP_ADD_INT_2ADDR:
+ armOp = ARMV5TE_ADD_RRR;
+ break;
+ case OP_SUB_INT:
+ case OP_SUB_INT_2ADDR:
+ armOp = ARMV5TE_SUB_RRR;
+ break;
+ case OP_MUL_INT:
+ case OP_MUL_INT_2ADDR:
+ armOp = ARMV5TE_MUL;
+ break;
+ case OP_DIV_INT:
+ case OP_DIV_INT_2ADDR:
+ callOut = true;
+ checkZero = true;
+ callTgt = __aeabi_idiv;
+ retReg = r0;
+ break;
+ /* NOTE: returns in r1 */
+ case OP_REM_INT:
+ case OP_REM_INT_2ADDR:
+ callOut = true;
+ checkZero = true;
+ callTgt = __aeabi_idivmod;
+ retReg = r1;
+ break;
+ case OP_AND_INT:
+ case OP_AND_INT_2ADDR:
+ armOp = ARMV5TE_AND_RR;
+ break;
+ case OP_OR_INT:
+ case OP_OR_INT_2ADDR:
+ armOp = ARMV5TE_ORR;
+ break;
+ case OP_XOR_INT:
+ case OP_XOR_INT_2ADDR:
+ armOp = ARMV5TE_EOR;
+ break;
+ case OP_SHL_INT:
+ case OP_SHL_INT_2ADDR:
+ armOp = ARMV5TE_LSLV;
+ break;
+ case OP_SHR_INT:
+ case OP_SHR_INT_2ADDR:
+ armOp = ARMV5TE_ASRV;
+ break;
+ case OP_USHR_INT:
+ case OP_USHR_INT_2ADDR:
+ armOp = ARMV5TE_LSRV;
+ break;
+ default:
+ LOGE("Invalid word arith op: 0x%x(%d)",
+ mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
+ dvmAbort();
+ }
+ if (!callOut) {
+ /* Try to allocate reg0 to the currently cached source operand */
+ if (cUnit->registerScoreboard.liveDalvikReg == vSrc1) {
+ reg0 = selectFirstRegister(cUnit, vSrc1, false);
+ reg1 = NEXT_REG(reg0);
+ regDest = NEXT_REG(reg1);
+
+ loadValue(cUnit, vSrc1, reg0); /* Should be optimized away */
+ loadValue(cUnit, vSrc2, reg1);
+ genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
+ } else {
+ reg0 = selectFirstRegister(cUnit, vSrc2, false);
+ reg1 = NEXT_REG(reg0);
+ regDest = NEXT_REG(reg1);
+
+ loadValue(cUnit, vSrc1, reg1); /* Load this value first */
+ loadValue(cUnit, vSrc2, reg0); /* May be optimized away */
+ genBinaryOp(cUnit, vDest, armOp, reg1, reg0, regDest);
+ }
+ } else {
+ /*
+ * Load the callout target first since it will never be eliminated
+ * and its value will be used first.
+ */
+ loadConstant(cUnit, r2, (int) callTgt);
+ /*
+ * Load vSrc2 first if it is not cached in a native register or it
+ * is in r0 which will be clobbered if vSrc1 is loaded first.
+ */
+ if (cUnit->registerScoreboard.liveDalvikReg != vSrc2 ||
+ cUnit->registerScoreboard.nativeReg == r0) {
+ /* Cannot be optimized and won't clobber r0 */
+ loadValue(cUnit, vSrc2, r1);
+ /* May be optimized if vSrc1 is cached */
+ loadValue(cUnit, vSrc1, r0);
+ } else {
+ loadValue(cUnit, vSrc1, r0);
+ loadValue(cUnit, vSrc2, r1);
+ }
+ if (checkZero) {
+ genNullCheck(cUnit, vSrc2, r1, mir->offset, NULL);
+ }
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ storeValue(cUnit, retReg, vDest, r2);
+ }
+ return false;
+}
+
+static bool genArithOp(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ int vA = mir->dalvikInsn.vA;
+ int vB = mir->dalvikInsn.vB;
+ int vC = mir->dalvikInsn.vC;
+
+ if ((opCode >= OP_ADD_LONG_2ADDR) && (opCode <= OP_XOR_LONG_2ADDR)) {
+ return genArithOpLong(cUnit,mir, vA, vA, vB);
+ }
+ if ((opCode >= OP_ADD_LONG) && (opCode <= OP_XOR_LONG)) {
+ return genArithOpLong(cUnit,mir, vA, vB, vC);
+ }
+ if ((opCode >= OP_SHL_LONG_2ADDR) && (opCode <= OP_USHR_LONG_2ADDR)) {
+ return genShiftOpLong(cUnit,mir, vA, vA, vB);
+ }
+ if ((opCode >= OP_SHL_LONG) && (opCode <= OP_USHR_LONG)) {
+ return genShiftOpLong(cUnit,mir, vA, vB, vC);
+ }
+ if ((opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_USHR_INT_2ADDR)) {
+ return genArithOpInt(cUnit,mir, vA, vA, vB);
+ }
+ if ((opCode >= OP_ADD_INT) && (opCode <= OP_USHR_INT)) {
+ return genArithOpInt(cUnit,mir, vA, vB, vC);
+ }
+ if ((opCode >= OP_ADD_FLOAT_2ADDR) && (opCode <= OP_REM_FLOAT_2ADDR)) {
+ return dvmCompilerGenArithOpFloat(cUnit,mir, vA, vA, vB);
+ }
+ if ((opCode >= OP_ADD_FLOAT) && (opCode <= OP_REM_FLOAT)) {
+ return dvmCompilerGenArithOpFloat(cUnit, mir, vA, vB, vC);
+ }
+ if ((opCode >= OP_ADD_DOUBLE_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
+ return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vA, vB);
+ }
+ if ((opCode >= OP_ADD_DOUBLE) && (opCode <= OP_REM_DOUBLE)) {
+ return dvmCompilerGenArithOpDouble(cUnit,mir, vA, vB, vC);
+ }
+ return true;
+}
+
+static bool genConversionCall(CompilationUnit *cUnit, MIR *mir, void *funct,
+ int srcSize, int tgtSize)
+{
+ /*
+ * Don't optimize the register usage since it calls out to template
+ * functions
+ */
+ loadConstant(cUnit, r2, (int)funct);
+ if (srcSize == 1) {
+ loadValue(cUnit, mir->dalvikInsn.vB, r0);
+ } else {
+ loadValuePair(cUnit, mir->dalvikInsn.vB, r0, r1);
+ }
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ if (tgtSize == 1) {
+ storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+ } else {
+ storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
+ }
+ return false;
+}
+
+/* Experimental example of completely inlining a native replacement */
+static bool genInlinedStringLength(CompilationUnit *cUnit, MIR *mir)
+{
+ /* Don't optimize the register usage */
+ int offset = (int) &((InterpState *) NULL)->retval;
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ assert(dInsn->vA == 1);
+ loadValue(cUnit, dInsn->arg[0], r0);
+ loadConstant(cUnit, r1, gDvm.offJavaLangString_count);
+ genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset, NULL);
+ newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r1);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
+ return false;
+}
+
+static void genProcessArgsNoRange(CompilationUnit *cUnit, MIR *mir,
+ DecodedInstruction *dInsn,
+ Armv5teLIR **pcrLabel)
+{
+ unsigned int i;
+ unsigned int regMask = 0;
+
+ /* Load arguments to r0..r4 */
+ for (i = 0; i < dInsn->vA; i++) {
+ regMask |= 1 << i;
+ loadValue(cUnit, dInsn->arg[i], i);
+ }
+ if (regMask) {
+ /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
+ newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
+ sizeof(StackSaveArea) + (dInsn->vA << 2));
+ /* generate null check */
+ if (pcrLabel) {
+ *pcrLabel = genNullCheck(cUnit, dInsn->arg[0], r0, mir->offset,
+ NULL);
+ }
+ newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
+ }
+}
+
+static void genProcessArgsRange(CompilationUnit *cUnit, MIR *mir,
+ DecodedInstruction *dInsn,
+ Armv5teLIR **pcrLabel)
+{
+ int srcOffset = dInsn->vC << 2;
+ int numArgs = dInsn->vA;
+ int regMask;
+ /*
+ * r4PC : &rFP[vC]
+ * r7: &newFP[0]
+ */
+ if (srcOffset < 8) {
+ newLIR3(cUnit, ARMV5TE_ADD_RRI3, r4PC, rFP, srcOffset);
+ } else {
+ loadConstant(cUnit, r4PC, srcOffset);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, rFP, r4PC);
+ }
+ /* load [r0 .. min(numArgs,4)] */
+ regMask = (1 << ((numArgs < 4) ? numArgs : 4)) - 1;
+ newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
+
+ if (sizeof(StackSaveArea) + (numArgs << 2) < 256) {
+ newLIR2(cUnit, ARMV5TE_MOV_RR, r7, rFP);
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, r7,
+ sizeof(StackSaveArea) + (numArgs << 2));
+ } else {
+ loadConstant(cUnit, r7, sizeof(StackSaveArea) + (numArgs << 2));
+ newLIR3(cUnit, ARMV5TE_SUB_RRR, r7, rFP, r7);
+ }
+
+ /* generate null check */
+ if (pcrLabel) {
+ *pcrLabel = genNullCheck(cUnit, dInsn->vC, r0, mir->offset, NULL);
+ }
+
+ /*
+ * Handle remaining 4n arguments:
+ * store previously loaded 4 values and load the next 4 values
+ */
+ if (numArgs >= 8) {
+ Armv5teLIR *loopLabel = NULL;
+ /*
+ * r0 contains "this" and it will be used later, so push it to the stack
+ * first. Pushing r5 is just for stack alignment purposes.
+ */
+ newLIR1(cUnit, ARMV5TE_PUSH, 1 << r0 | 1 << 5);
+ /* No need to generate the loop structure if numArgs <= 11 */
+ if (numArgs > 11) {
+ loadConstant(cUnit, 5, ((numArgs - 4) >> 2) << 2);
+ loopLabel = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
+ }
+ newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
+ newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
+ /* No need to generate the loop structure if numArgs <= 11 */
+ if (numArgs > 11) {
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, 5, 4);
+ genConditionalBranch(cUnit, ARM_COND_NE, loopLabel);
+ }
+ }
+
+ /* Save the last batch of loaded values */
+ newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
+
+ /* Generate the loop epilogue - don't use r0 */
+ if ((numArgs > 4) && (numArgs % 4)) {
+ regMask = ((1 << (numArgs & 0x3)) - 1) << 1;
+ newLIR2(cUnit, ARMV5TE_LDMIA, r4PC, regMask);
+ }
+ if (numArgs >= 8)
+ newLIR1(cUnit, ARMV5TE_POP, 1 << r0 | 1 << 5);
+
+ /* Save the modulo 4 arguments */
+ if ((numArgs > 4) && (numArgs % 4)) {
+ newLIR2(cUnit, ARMV5TE_STMIA, r7, regMask);
+ }
+}
+
+static void genInvokeCommon(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+ Armv5teLIR *labelList, Armv5teLIR *pcrLabel,
+ const Method *calleeMethod)
+{
+ Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
+
+ /* r1 = &retChainingCell */
+ Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
+ r1, 0);
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ /*
+ * r0 = calleeMethod (loaded upon calling genInvokeCommon)
+ * r1 = &ChainingCell
+ * r4PC = callsiteDPC
+ */
+ if (dvmIsNativeMethod(calleeMethod)) {
+ genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(INVOKE_STATS)
+ gDvmJit.invokeNoOpt++;
+#endif
+ } else {
+ genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_CHAIN);
+#if defined(INVOKE_STATS)
+ gDvmJit.invokeChain++;
+#endif
+ genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+ }
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+}
+
+/* Geneate a branch to go back to the interpreter */
+static void genPuntToInterp(CompilationUnit *cUnit, unsigned int offset)
+{
+ /* r0 = dalvik pc */
+ loadConstant(cUnit, r0, (int) (cUnit->method->insns + offset));
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
+ offsetof(InterpState, jitToInterpEntries.dvmJitToInterpPunt) >> 2);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r1);
+}
+
+/*
+ * Attempt to single step one instruction using the interpreter and return
+ * to the compiled code for the next Dalvik instruction
+ */
+static void genInterpSingleStep(CompilationUnit *cUnit, MIR *mir)
+{
+ int flags = dexGetInstrFlags(gDvm.instrFlags, mir->dalvikInsn.opCode);
+ int flagsToCheck = kInstrCanBranch | kInstrCanSwitch | kInstrCanReturn |
+ kInstrCanThrow;
+ if ((mir->next == NULL) || (flags & flagsToCheck)) {
+ genPuntToInterp(cUnit, mir->offset);
+ return;
+ }
+ int entryAddr = offsetof(InterpState,
+ jitToInterpEntries.dvmJitToInterpSingleStep);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE, entryAddr >> 2);
+ /* r0 = dalvik pc */
+ loadConstant(cUnit, r0, (int) (cUnit->method->insns + mir->offset));
+ /* r1 = dalvik pc of following instruction */
+ loadConstant(cUnit, r1, (int) (cUnit->method->insns + mir->next->offset));
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+}
+
+
+/*****************************************************************************/
+/*
+ * The following are the first-level codegen routines that analyze the format
+ * of each bytecode then either dispatch special purpose codegen routines
+ * or produce corresponding Thumb instructions directly.
+ */
+
+static bool handleFmt10t_Fmt20t_Fmt30t(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb, Armv5teLIR *labelList)
+{
+ /* For OP_GOTO, OP_GOTO_16, and OP_GOTO_32 */
+ genUnconditionalBranch(cUnit, &labelList[bb->taken->id]);
+ return false;
+}
+
+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_EC))) {
+ LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
+ return true;
+ }
+ switch (dalvikOpCode) {
+ case OP_RETURN_VOID:
+ genReturnCommon(cUnit,mir);
+ break;
+ case OP_UNUSED_73:
+ case OP_UNUSED_79:
+ case OP_UNUSED_7A:
+ LOGE("Codegen: got unused opcode 0x%x\n",dalvikOpCode);
+ return true;
+ case OP_NOP:
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt11n_Fmt31i(CompilationUnit *cUnit, MIR *mir)
+{
+ int reg0, reg1, reg2;
+
+ switch (mir->dalvikInsn.opCode) {
+ case OP_CONST:
+ case OP_CONST_4: {
+ /* Avoid using the previously used register */
+ reg0 = selectFirstRegister(cUnit, vNone, false);
+ reg1 = NEXT_REG(reg0);
+ loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
+ storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
+ break;
+ }
+ case OP_CONST_WIDE_32: {
+ /* Avoid using the previously used register */
+ reg0 = selectFirstRegister(cUnit, vNone, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ loadConstant(cUnit, reg0, mir->dalvikInsn.vB);
+ newLIR3(cUnit, ARMV5TE_ASR, reg1, reg0, 31);
+ storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt21h(CompilationUnit *cUnit, MIR *mir)
+{
+ int reg0, reg1, reg2;
+
+ /* Avoid using the previously used register */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_CONST_HIGH16: {
+ reg0 = selectFirstRegister(cUnit, vNone, false);
+ reg1 = NEXT_REG(reg0);
+ loadConstant(cUnit, reg0, mir->dalvikInsn.vB << 16);
+ storeValue(cUnit, reg0, mir->dalvikInsn.vA, reg1);
+ break;
+ }
+ case OP_CONST_WIDE_HIGH16: {
+ reg0 = selectFirstRegister(cUnit, vNone, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ loadConstant(cUnit, reg1, mir->dalvikInsn.vB << 16);
+ loadConstant(cUnit, reg0, 0);
+ storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt20bc(CompilationUnit *cUnit, MIR *mir)
+{
+ /* For OP_THROW_VERIFICATION_ERROR */
+ genInterpSingleStep(cUnit, mir);
+ return false;
+}
+
+static bool handleFmt21c_Fmt31c(CompilationUnit *cUnit, MIR *mir)
+{
+ /* Native register to use if the interested value is vA */
+ int regvA = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
+ /* Native register to use if source is not from Dalvik registers */
+ int regvNone = selectFirstRegister(cUnit, vNone, false);
+ /* Similar to regvA but for 64-bit values */
+ int regvAWide = selectFirstRegister(cUnit, mir->dalvikInsn.vA, true);
+ /* Similar to regvNone but for 64-bit values */
+ int regvNoneWide = selectFirstRegister(cUnit, vNone, true);
+
+ switch (mir->dalvikInsn.opCode) {
+ /*
+ * TODO: Verify that we can ignore the resolution check here because
+ * it will have already successfully been interpreted once
+ */
+ case OP_CONST_STRING_JUMBO:
+ case OP_CONST_STRING: {
+ void *strPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResStrings[mir->dalvikInsn.vB]);
+ assert(strPtr != NULL);
+ loadConstant(cUnit, regvNone, (int) strPtr );
+ storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
+ break;
+ }
+ /*
+ * TODO: Verify that we can ignore the resolution check here because
+ * it will have already successfully been interpreted once
+ */
+ case OP_CONST_CLASS: {
+ void *classPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+ assert(classPtr != NULL);
+ loadConstant(cUnit, regvNone, (int) classPtr );
+ storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
+ break;
+ }
+ case OP_SGET_OBJECT:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_CHAR:
+ case OP_SGET_BYTE:
+ case OP_SGET_SHORT:
+ case OP_SGET: {
+ int valOffset = (int)&((struct StaticField*)NULL)->value;
+ void *fieldPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ assert(fieldPtr != NULL);
+ loadConstant(cUnit, regvNone, (int) fieldPtr + valOffset);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, regvNone, regvNone, 0);
+ storeValue(cUnit, regvNone, mir->dalvikInsn.vA, NEXT_REG(regvNone));
+ break;
+ }
+ case OP_SGET_WIDE: {
+ int valOffset = (int)&((struct StaticField*)NULL)->value;
+ void *fieldPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+ int reg0, reg1, reg2;
+
+ assert(fieldPtr != NULL);
+ reg0 = regvNoneWide;
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
+ newLIR2(cUnit, ARMV5TE_LDMIA, reg2, (1<<reg0 | 1<<reg1));
+ storeValuePair(cUnit, reg0, reg1, mir->dalvikInsn.vA, reg2);
+ break;
+ }
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_SHORT:
+ case OP_SPUT: {
+ int valOffset = (int)&((struct StaticField*)NULL)->value;
+ void *fieldPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ assert(fieldPtr != NULL);
+ loadValue(cUnit, mir->dalvikInsn.vA, regvA);
+ updateLiveRegister(cUnit, mir->dalvikInsn.vA, regvA);
+ loadConstant(cUnit, NEXT_REG(regvA), (int) fieldPtr + valOffset);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, regvA, NEXT_REG(regvA), 0);
+ break;
+ }
+ case OP_SPUT_WIDE: {
+ int reg0, reg1, reg2;
+ int valOffset = (int)&((struct StaticField*)NULL)->value;
+ void *fieldPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vB]);
+
+ assert(fieldPtr != NULL);
+ reg0 = regvAWide;
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ loadValuePair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
+ updateLiveRegisterPair(cUnit, mir->dalvikInsn.vA, reg0, reg1);
+ loadConstant(cUnit, reg2, (int) fieldPtr + valOffset);
+ newLIR2(cUnit, ARMV5TE_STMIA, reg2, (1<<reg0 | 1<<reg1));
+ break;
+ }
+ case OP_NEW_INSTANCE: {
+ /*
+ * Obey the calling convention and don't mess with the register
+ * usage.
+ */
+ ClassObject *classPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+ assert(classPtr != NULL);
+ assert(classPtr->status & CLASS_INITIALIZED);
+ if ((classPtr->accessFlags & (ACC_INTERFACE|ACC_ABSTRACT)) != 0) {
+ /* It's going to throw, just let the interp. deal with it. */
+ genInterpSingleStep(cUnit, mir);
+ return false;
+ }
+ loadConstant(cUnit, r4PC, (int)dvmAllocObject);
+ loadConstant(cUnit, r0, (int) classPtr);
+ genExportPC(cUnit, mir, r2, r3 );
+ loadConstant(cUnit, r1, ALLOC_DONT_TRACK);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ /*
+ * TODO: As coded, we'll bail and reinterpret on alloc failure.
+ * Need a general mechanism to bail to thrown exception code.
+ */
+ genZeroCheck(cUnit, r0, mir->offset, NULL);
+ storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+ break;
+ }
+ case OP_CHECK_CAST: {
+ /*
+ * Obey the calling convention and don't mess with the register
+ * usage.
+ */
+ ClassObject *classPtr =
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vB]);
+ loadConstant(cUnit, r1, (int) classPtr );
+ loadValue(cUnit, mir->dalvikInsn.vA, r0); /* Ref */
+ /*
+ * TODO - in theory classPtr should be resoved by the time this
+ * instruction made into a trace, but we are seeing NULL at runtime
+ * so this check is temporarily used as a workaround.
+ */
+ Armv5teLIR * pcrLabel = genZeroCheck(cUnit, r1, mir->offset, NULL);
+ newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
+ Armv5teLIR *branch1 =
+ newLIR2(cUnit, ARMV5TE_B_COND, 4, ARM_COND_EQ);
+ /* r0 now contains object->clazz */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
+ offsetof(Object, clazz) >> 2);
+ loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
+ newLIR2(cUnit, ARMV5TE_CMP_RR, r0, r1);
+ Armv5teLIR *branch2 =
+ newLIR2(cUnit, ARMV5TE_B_COND, 2, ARM_COND_EQ);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ /* check cast failed - punt to the interpreter */
+ genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
+ /* check cast passed - branch target here */
+ Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
+ branch1->generic.target = (LIR *)target;
+ branch2->generic.target = (LIR *)target;
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt11x(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ switch (dalvikOpCode) {
+ case OP_MOVE_EXCEPTION: {
+ int offset = offsetof(InterpState, self);
+ int exOffset = offsetof(Thread, exception);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, offset >> 2);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r1, exOffset >> 2);
+ storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+ break;
+ }
+ case OP_MOVE_RESULT:
+ case OP_MOVE_RESULT_OBJECT: {
+ int offset = offsetof(InterpState, retval);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
+ storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+ break;
+ }
+ case OP_MOVE_RESULT_WIDE: {
+ int offset = offsetof(InterpState, retval);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE, (offset >> 2)+1);
+ storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
+ break;
+ }
+ case OP_RETURN_WIDE: {
+ loadValuePair(cUnit, mir->dalvikInsn.vA, r0, r1);
+ int offset = offsetof(InterpState, retval);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, rGLUE, (offset >> 2)+1);
+ genReturnCommon(cUnit,mir);
+ break;
+ }
+ case OP_RETURN:
+ case OP_RETURN_OBJECT: {
+ loadValue(cUnit, mir->dalvikInsn.vA, r0);
+ int offset = offsetof(InterpState, retval);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, r0, rGLUE, offset >> 2);
+ genReturnCommon(cUnit,mir);
+ break;
+ }
+ /*
+ * TODO-VERIFY: May be playing a bit fast and loose here. As coded,
+ * a failure on lock/unlock will cause us to revert to the interpeter
+ * to try again. This means we essentially ignore the first failure on
+ * the assumption that the interpreter will correctly handle the 2nd.
+ */
+ case OP_MONITOR_ENTER:
+ case OP_MONITOR_EXIT: {
+ int offset = offsetof(InterpState, self);
+ loadValue(cUnit, mir->dalvikInsn.vA, r1);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE, offset >> 2);
+ if (dalvikOpCode == OP_MONITOR_ENTER) {
+ loadConstant(cUnit, r2, (int)dvmLockObject);
+ } else {
+ loadConstant(cUnit, r2, (int)dvmUnlockObject);
+ }
+ /*
+ * TODO-VERIFY: Note that we're not doing an EXPORT_PC, as
+ * Lock/unlock won't throw, and this code does not support
+ * DEADLOCK_PREDICTION or MONITOR_TRACKING. Should it?
+ */
+ genNullCheck(cUnit, mir->dalvikInsn.vA, r1, mir->offset, NULL);
+ /* Do the call */
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ break;
+ }
+ case OP_THROW: {
+ genInterpSingleStep(cUnit, mir);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+bool dvmCompilerGenConversionPortable(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+
+ float __aeabi_i2f( int op1 );
+ int __aeabi_f2iz( float op1 );
+ float __aeabi_d2f( double op1 );
+ double __aeabi_f2d( float op1 );
+ double __aeabi_i2d( int op1 );
+ int __aeabi_d2iz( double op1 );
+ long __aeabi_f2lz( float op1 );
+ float __aeabi_l2f( long op1 );
+ long __aeabi_d2lz( double op1 );
+ double __aeabi_l2d( long op1 );
+
+ switch (opCode) {
+ case OP_INT_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_i2f, 1, 1);
+ case OP_FLOAT_TO_INT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_f2iz, 1, 1);
+ case OP_DOUBLE_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_d2f, 2, 1);
+ case OP_FLOAT_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_f2d, 1, 2);
+ case OP_INT_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_i2d, 1, 2);
+ case OP_DOUBLE_TO_INT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_d2iz, 2, 1);
+ case OP_FLOAT_TO_LONG:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_f2lz, 1, 2);
+ case OP_LONG_TO_FLOAT:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_l2f, 2, 1);
+ case OP_DOUBLE_TO_LONG:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_d2lz, 2, 2);
+ case OP_LONG_TO_DOUBLE:
+ return genConversionCall(cUnit, mir, (void*)__aeabi_l2d, 2, 2);
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt12x(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ int vSrc1Dest = mir->dalvikInsn.vA;
+ int vSrc2 = mir->dalvikInsn.vB;
+ int reg0, reg1, reg2;
+
+ /* TODO - find the proper include file to declare these */
+
+ if ( (opCode >= OP_ADD_INT_2ADDR) && (opCode <= OP_REM_DOUBLE_2ADDR)) {
+ return genArithOp( cUnit, mir );
+ }
+
+ /*
+ * If data type is 64-bit, re-calculate the register numbers in the
+ * corresponding cases.
+ */
+ reg0 = selectFirstRegister(cUnit, vSrc2, false);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+
+ switch (opCode) {
+ case OP_INT_TO_FLOAT:
+ case OP_FLOAT_TO_INT:
+ case OP_DOUBLE_TO_FLOAT:
+ case OP_FLOAT_TO_DOUBLE:
+ case OP_INT_TO_DOUBLE:
+ case OP_DOUBLE_TO_INT:
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ case OP_LONG_TO_DOUBLE:
+ return dvmCompilerGenConversion(cUnit, mir);
+ case OP_NEG_INT:
+ case OP_NOT_INT:
+ return genArithOpInt(cUnit, mir, vSrc1Dest, vSrc1Dest, vSrc2);
+ case OP_NEG_LONG:
+ case OP_NOT_LONG:
+ return genArithOpLong(cUnit,mir, vSrc1Dest, vSrc1Dest, vSrc2);
+ case OP_NEG_FLOAT:
+ return dvmCompilerGenArithOpFloat(cUnit, mir, vSrc1Dest,
+ vSrc1Dest, vSrc2);
+ case OP_NEG_DOUBLE:
+ return dvmCompilerGenArithOpDouble(cUnit, mir, vSrc1Dest,
+ vSrc1Dest, vSrc2);
+ case OP_MOVE_WIDE: {
+ reg0 = selectFirstRegister(cUnit, vSrc2, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+
+ loadValuePair(cUnit, vSrc2, reg0, reg1);
+ storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
+ break;
+ }
+ case OP_INT_TO_LONG: {
+ reg0 = selectFirstRegister(cUnit, vSrc2, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+
+ loadValue(cUnit, mir->dalvikInsn.vB, reg0);
+ newLIR3(cUnit, ARMV5TE_ASR, reg1, reg0, 31);
+ storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
+ break;
+ }
+ case OP_MOVE:
+ case OP_MOVE_OBJECT:
+ case OP_LONG_TO_INT:
+ loadValue(cUnit, vSrc2, reg0);
+ storeValue(cUnit, reg0, vSrc1Dest, reg1);
+ break;
+ case OP_INT_TO_BYTE:
+ loadValue(cUnit, vSrc2, reg0);
+ newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 24);
+ newLIR3(cUnit, ARMV5TE_ASR, reg0, reg0, 24);
+ storeValue(cUnit, reg0, vSrc1Dest, reg1);
+ break;
+ case OP_INT_TO_SHORT:
+ loadValue(cUnit, vSrc2, reg0);
+ newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 16);
+ newLIR3(cUnit, ARMV5TE_ASR, reg0, reg0, 16);
+ storeValue(cUnit, reg0, vSrc1Dest, reg1);
+ break;
+ case OP_INT_TO_CHAR:
+ loadValue(cUnit, vSrc2, reg0);
+ newLIR3(cUnit, ARMV5TE_LSL, reg0, reg0, 16);
+ newLIR3(cUnit, ARMV5TE_LSR, reg0, reg0, 16);
+ storeValue(cUnit, reg0, vSrc1Dest, reg1);
+ break;
+ case OP_ARRAY_LENGTH: {
+ int lenOffset = offsetof(ArrayObject, length);
+ loadValue(cUnit, vSrc2, reg0);
+ genNullCheck(cUnit, vSrc2, reg0, mir->offset, NULL);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, reg0, reg0, lenOffset >> 2);
+ storeValue(cUnit, reg0, vSrc1Dest, reg1);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt21s(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ int reg0, reg1, reg2;
+
+ /* It takes few instructions to handle OP_CONST_WIDE_16 inline */
+ if (dalvikOpCode == OP_CONST_WIDE_16) {
+ int vDest = mir->dalvikInsn.vA;
+ int BBBB = mir->dalvikInsn.vB;
+
+ reg0 = selectFirstRegister(cUnit, vNone, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+
+ loadConstant(cUnit, reg0, BBBB);
+ loadConstant(cUnit, reg1, 0);
+ if (BBBB < 0) {
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, reg1, -1);
+ }
+
+ /* Save the long values to the specified Dalvik register pair */
+ storeValuePair(cUnit, reg0, reg1, vDest, reg2);
+ } else if (dalvikOpCode == OP_CONST_16) {
+ int vDest = mir->dalvikInsn.vA;
+ int BBBB = mir->dalvikInsn.vB;
+
+ reg0 = selectFirstRegister(cUnit, vNone, false);
+ reg1 = NEXT_REG(reg0);
+
+ loadConstant(cUnit, reg0, BBBB);
+ storeValue(cUnit, reg0, vDest, reg1);
+ } else {
+ return true;
+ }
+ return false;
+}
+
+/* Compare agaist zero */
+static bool handleFmt21t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+ Armv5teLIR *labelList)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ Armv5teConditionCode cond;
+ int reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
+
+ loadValue(cUnit, mir->dalvikInsn.vA, reg0);
+ newLIR2(cUnit, ARMV5TE_CMP_RI8, reg0, 0);
+
+ switch (dalvikOpCode) {
+ case OP_IF_EQZ:
+ cond = ARM_COND_EQ;
+ break;
+ case OP_IF_NEZ:
+ cond = ARM_COND_NE;
+ break;
+ case OP_IF_LTZ:
+ cond = ARM_COND_LT;
+ break;
+ case OP_IF_GEZ:
+ cond = ARM_COND_GE;
+ break;
+ case OP_IF_GTZ:
+ cond = ARM_COND_GT;
+ break;
+ case OP_IF_LEZ:
+ cond = ARM_COND_LE;
+ break;
+ default:
+ cond = 0;
+ LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
+ dvmAbort();
+ }
+ genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+ /* This mostly likely will be optimized away in a later phase */
+ genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+ return false;
+}
+
+static bool handleFmt22b_Fmt22s(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ int vSrc = mir->dalvikInsn.vB;
+ int vDest = mir->dalvikInsn.vA;
+ int lit = mir->dalvikInsn.vC;
+ int armOp;
+ int reg0, reg1, regDest;
+
+ reg0 = selectFirstRegister(cUnit, vSrc, false);
+ reg1 = NEXT_REG(reg0);
+ regDest = NEXT_REG(reg1);
+
+ /* TODO: find the proper .h file to declare these */
+ int __aeabi_idivmod(int op1, int op2);
+ int __aeabi_idiv(int op1, int op2);
+
+ switch (dalvikOpCode) {
+ case OP_ADD_INT_LIT8:
+ case OP_ADD_INT_LIT16:
+ loadValue(cUnit, vSrc, reg0);
+ if (lit <= 7 && lit >= 0) {
+ newLIR3(cUnit, ARMV5TE_ADD_RRI3, regDest, reg0, lit);
+ storeValue(cUnit, regDest, vDest, reg1);
+ } else if (lit <= 255 && lit >= 0) {
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, reg0, lit);
+ storeValue(cUnit, reg0, vDest, reg1);
+ } else if (lit >= -7 && lit <= 0) {
+ /* Convert to a small constant subtraction */
+ newLIR3(cUnit, ARMV5TE_SUB_RRI3, regDest, reg0, -lit);
+ storeValue(cUnit, regDest, vDest, reg1);
+ } else if (lit >= -255 && lit <= 0) {
+ /* Convert to a small constant subtraction */
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, reg0, -lit);
+ storeValue(cUnit, reg0, vDest, reg1);
+ } else {
+ loadConstant(cUnit, reg1, lit);
+ genBinaryOp(cUnit, vDest, ARMV5TE_ADD_RRR, reg0, reg1, regDest);
+ }
+ break;
+
+ case OP_RSUB_INT_LIT8:
+ case OP_RSUB_INT:
+ loadValue(cUnit, vSrc, reg1);
+ loadConstant(cUnit, reg0, lit);
+ genBinaryOp(cUnit, vDest, ARMV5TE_SUB_RRR, reg0, reg1, regDest);
+ break;
+
+ case OP_MUL_INT_LIT8:
+ case OP_MUL_INT_LIT16:
+ case OP_AND_INT_LIT8:
+ case OP_AND_INT_LIT16:
+ case OP_OR_INT_LIT8:
+ case OP_OR_INT_LIT16:
+ case OP_XOR_INT_LIT8:
+ case OP_XOR_INT_LIT16:
+ loadValue(cUnit, vSrc, reg0);
+ loadConstant(cUnit, reg1, lit);
+ switch (dalvikOpCode) {
+ case OP_MUL_INT_LIT8:
+ case OP_MUL_INT_LIT16:
+ armOp = ARMV5TE_MUL;
+ break;
+ case OP_AND_INT_LIT8:
+ case OP_AND_INT_LIT16:
+ armOp = ARMV5TE_AND_RR;
+ break;
+ case OP_OR_INT_LIT8:
+ case OP_OR_INT_LIT16:
+ armOp = ARMV5TE_ORR;
+ break;
+ case OP_XOR_INT_LIT8:
+ case OP_XOR_INT_LIT16:
+ armOp = ARMV5TE_EOR;
+ break;
+ default:
+ dvmAbort();
+ }
+ genBinaryOp(cUnit, vDest, armOp, reg0, reg1, regDest);
+ break;
+
+ case OP_SHL_INT_LIT8:
+ case OP_SHR_INT_LIT8:
+ case OP_USHR_INT_LIT8:
+ loadValue(cUnit, vSrc, reg0);
+ switch (dalvikOpCode) {
+ case OP_SHL_INT_LIT8:
+ armOp = ARMV5TE_LSL;
+ break;
+ case OP_SHR_INT_LIT8:
+ armOp = ARMV5TE_ASR;
+ break;
+ case OP_USHR_INT_LIT8:
+ armOp = ARMV5TE_LSR;
+ break;
+ default: dvmAbort();
+ }
+ newLIR3(cUnit, armOp, reg0, reg0, lit);
+ storeValue(cUnit, reg0, vDest, reg1);
+ break;
+
+ case OP_DIV_INT_LIT8:
+ case OP_DIV_INT_LIT16:
+ /* Register usage based on the calling convention */
+ if (lit == 0) {
+ /* Let the interpreter deal with div by 0 */
+ genInterpSingleStep(cUnit, mir);
+ return false;
+ }
+ loadConstant(cUnit, r2, (int)__aeabi_idiv);
+ loadConstant(cUnit, r1, lit);
+ loadValue(cUnit, vSrc, r0);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ storeValue(cUnit, r0, vDest, r2);
+ break;
+
+ case OP_REM_INT_LIT8:
+ case OP_REM_INT_LIT16:
+ /* Register usage based on the calling convention */
+ if (lit == 0) {
+ /* Let the interpreter deal with div by 0 */
+ genInterpSingleStep(cUnit, mir);
+ return false;
+ }
+ loadConstant(cUnit, r2, (int)__aeabi_idivmod);
+ loadConstant(cUnit, r1, lit);
+ loadValue(cUnit, vSrc, r0);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ storeValue(cUnit, r1, vDest, r2);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt22c(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ int fieldOffset;
+
+ if (dalvikOpCode >= OP_IGET && dalvikOpCode <= OP_IPUT_SHORT) {
+ InstField *pInstField = (InstField *)
+ cUnit->method->clazz->pDvmDex->pResFields[mir->dalvikInsn.vC];
+ int fieldOffset;
+
+ assert(pInstField != NULL);
+ fieldOffset = pInstField->byteOffset;
+ } else {
+ /* To make the compiler happy */
+ fieldOffset = 0;
+ }
+ switch (dalvikOpCode) {
+ /*
+ * TODO: I may be assuming too much here.
+ * Verify what is known at JIT time.
+ */
+ case OP_NEW_ARRAY: {
+ void *classPtr = (void*)
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
+ assert(classPtr != NULL);
+ loadValue(cUnit, mir->dalvikInsn.vB, r1); /* Len */
+ loadConstant(cUnit, r0, (int) classPtr );
+ loadConstant(cUnit, r4PC, (int)dvmAllocArrayByClass);
+ Armv5teLIR *pcrLabel =
+ genRegImmCheck(cUnit, ARM_COND_MI, r1, 0, mir->offset, NULL);
+ genExportPC(cUnit, mir, r2, r3 );
+ newLIR2(cUnit, ARMV5TE_MOV_IMM,r2,ALLOC_DONT_TRACK);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ /*
+ * TODO: As coded, we'll bail and reinterpret on alloc failure.
+ * Need a general mechanism to bail to thrown exception code.
+ */
+ genZeroCheck(cUnit, r0, mir->offset, pcrLabel);
+ storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+ break;
+ }
+ /*
+ * TODO: I may be assuming too much here.
+ * Verify what is known at JIT time.
+ */
+ case OP_INSTANCE_OF: {
+ ClassObject *classPtr =
+ (cUnit->method->clazz->pDvmDex->pResClasses[mir->dalvikInsn.vC]);
+ assert(classPtr != NULL);
+ loadValue(cUnit, mir->dalvikInsn.vB, r0); /* Ref */
+ loadConstant(cUnit, r2, (int) classPtr );
+ newLIR2(cUnit, ARMV5TE_CMP_RI8, r0, 0); /* Null? */
+ /* When taken r0 has NULL which can be used for store directly */
+ Armv5teLIR *branch1 = newLIR2(cUnit, ARMV5TE_B_COND, 4,
+ ARM_COND_EQ);
+ /* r1 now contains object->clazz */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0,
+ offsetof(Object, clazz) >> 2);
+ loadConstant(cUnit, r4PC, (int)dvmInstanceofNonTrivial);
+ loadConstant(cUnit, r0, 1); /* Assume true */
+ newLIR2(cUnit, ARMV5TE_CMP_RR, r1, r2);
+ Armv5teLIR *branch2 = newLIR2(cUnit, ARMV5TE_B_COND, 2,
+ ARM_COND_EQ);
+ newLIR2(cUnit, ARMV5TE_MOV_RR, r0, r1);
+ newLIR2(cUnit, ARMV5TE_MOV_RR, r1, r2);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ /* branch target here */
+ Armv5teLIR *target = newLIR0(cUnit, ARMV5TE_PSEUDO_TARGET_LABEL);
+ storeValue(cUnit, r0, mir->dalvikInsn.vA, r1);
+ branch1->generic.target = (LIR *)target;
+ branch2->generic.target = (LIR *)target;
+ break;
+ }
+ case OP_IGET_WIDE:
+ genIGetWide(cUnit, mir, fieldOffset);
+ break;
+ case OP_IGET:
+ case OP_IGET_OBJECT:
+ genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
+ break;
+ case OP_IGET_BOOLEAN:
+ genIGet(cUnit, mir, ARMV5TE_LDRB_RRR, fieldOffset);
+ break;
+ case OP_IGET_BYTE:
+ genIGet(cUnit, mir, ARMV5TE_LDRSB_RRR, fieldOffset);
+ break;
+ case OP_IGET_CHAR:
+ genIGet(cUnit, mir, ARMV5TE_LDRH_RRR, fieldOffset);
+ break;
+ case OP_IGET_SHORT:
+ genIGet(cUnit, mir, ARMV5TE_LDRSH_RRR, fieldOffset);
+ break;
+ case OP_IPUT_WIDE:
+ genIPutWide(cUnit, mir, fieldOffset);
+ break;
+ case OP_IPUT:
+ case OP_IPUT_OBJECT:
+ genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
+ break;
+ case OP_IPUT_SHORT:
+ case OP_IPUT_CHAR:
+ genIPut(cUnit, mir, ARMV5TE_STRH_RRR, fieldOffset);
+ break;
+ case OP_IPUT_BYTE:
+ case OP_IPUT_BOOLEAN:
+ genIPut(cUnit, mir, ARMV5TE_STRB_RRR, fieldOffset);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt22cs(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ int fieldOffset = mir->dalvikInsn.vC;
+ switch (dalvikOpCode) {
+ case OP_IGET_QUICK:
+ case OP_IGET_OBJECT_QUICK:
+ genIGet(cUnit, mir, ARMV5TE_LDR_RRR, fieldOffset);
+ break;
+ case OP_IPUT_QUICK:
+ case OP_IPUT_OBJECT_QUICK:
+ genIPut(cUnit, mir, ARMV5TE_STR_RRR, fieldOffset);
+ break;
+ case OP_IGET_WIDE_QUICK:
+ genIGetWide(cUnit, mir, fieldOffset);
+ break;
+ case OP_IPUT_WIDE_QUICK:
+ genIPutWide(cUnit, mir, fieldOffset);
+ break;
+ default:
+ return true;
+ }
+ return false;
+
+}
+
+/* Compare agaist zero */
+static bool handleFmt22t(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+ Armv5teLIR *labelList)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ Armv5teConditionCode cond;
+ int reg0, reg1;
+
+ if (cUnit->registerScoreboard.liveDalvikReg == (int) mir->dalvikInsn.vA) {
+ reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vA, false);
+ reg1 = NEXT_REG(reg0);
+ /* Load vB first since vA can be fetched via a move */
+ loadValue(cUnit, mir->dalvikInsn.vB, reg1);
+ loadValue(cUnit, mir->dalvikInsn.vA, reg0);
+ } else {
+ reg0 = selectFirstRegister(cUnit, mir->dalvikInsn.vB, false);
+ reg1 = NEXT_REG(reg0);
+ /* Load vA first since vB can be fetched via a move */
+ loadValue(cUnit, mir->dalvikInsn.vA, reg0);
+ loadValue(cUnit, mir->dalvikInsn.vB, reg1);
+ }
+ newLIR2(cUnit, ARMV5TE_CMP_RR, reg0, reg1);
+
+ switch (dalvikOpCode) {
+ case OP_IF_EQ:
+ cond = ARM_COND_EQ;
+ break;
+ case OP_IF_NE:
+ cond = ARM_COND_NE;
+ break;
+ case OP_IF_LT:
+ cond = ARM_COND_LT;
+ break;
+ case OP_IF_GE:
+ cond = ARM_COND_GE;
+ break;
+ case OP_IF_GT:
+ cond = ARM_COND_GT;
+ break;
+ case OP_IF_LE:
+ cond = ARM_COND_LE;
+ break;
+ default:
+ cond = 0;
+ LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
+ dvmAbort();
+ }
+ genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
+ /* This mostly likely will be optimized away in a later phase */
+ genUnconditionalBranch(cUnit, &labelList[bb->fallThrough->id]);
+ return false;
+}
+
+static bool handleFmt22x_Fmt32x(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ int vSrc1Dest = mir->dalvikInsn.vA;
+ int vSrc2 = mir->dalvikInsn.vB;
+ int reg0, reg1, reg2;
+
+ switch (opCode) {
+ case OP_MOVE_16:
+ case OP_MOVE_OBJECT_16:
+ case OP_MOVE_FROM16:
+ case OP_MOVE_OBJECT_FROM16: {
+ reg0 = selectFirstRegister(cUnit, vSrc2, false);
+ reg1 = NEXT_REG(reg0);
+ loadValue(cUnit, vSrc2, reg0);
+ storeValue(cUnit, reg0, vSrc1Dest, reg1);
+ break;
+ }
+ case OP_MOVE_WIDE_16:
+ case OP_MOVE_WIDE_FROM16: {
+ reg0 = selectFirstRegister(cUnit, vSrc2, true);
+ reg1 = NEXT_REG(reg0);
+ reg2 = NEXT_REG(reg1);
+ loadValuePair(cUnit, vSrc2, reg0, reg1);
+ storeValuePair(cUnit, reg0, reg1, vSrc1Dest, reg2);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt23x(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ int vA = mir->dalvikInsn.vA;
+ int vB = mir->dalvikInsn.vB;
+ int vC = mir->dalvikInsn.vC;
+
+ /* Don't optimize for register usage since out-of-line handlers are used */
+ if ( (opCode >= OP_ADD_INT) && (opCode <= OP_REM_DOUBLE)) {
+ return genArithOp( cUnit, mir );
+ }
+
+ switch (opCode) {
+ case OP_CMPL_FLOAT:
+ case OP_CMPG_FLOAT:
+ case OP_CMPL_DOUBLE:
+ case OP_CMPG_DOUBLE:
+ return dvmCompilerGenCmpX(cUnit, mir, vA, vB, vC);
+ case OP_CMP_LONG:
+ loadValuePair(cUnit,vB, r0, r1);
+ loadValuePair(cUnit, vC, r2, r3);
+ genDispatchToHandler(cUnit, TEMPLATE_CMP_LONG);
+ storeValue(cUnit, r0, vA, r1);
+ break;
+ case OP_AGET_WIDE:
+ genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 3);
+ break;
+ case OP_AGET:
+ case OP_AGET_OBJECT:
+ genArrayGet(cUnit, mir, ARMV5TE_LDR_RRR, vB, vC, vA, 2);
+ break;
+ case OP_AGET_BOOLEAN:
+ genArrayGet(cUnit, mir, ARMV5TE_LDRB_RRR, vB, vC, vA, 0);
+ break;
+ case OP_AGET_BYTE:
+ genArrayGet(cUnit, mir, ARMV5TE_LDRSB_RRR, vB, vC, vA, 0);
+ break;
+ case OP_AGET_CHAR:
+ genArrayGet(cUnit, mir, ARMV5TE_LDRH_RRR, vB, vC, vA, 1);
+ break;
+ case OP_AGET_SHORT:
+ genArrayGet(cUnit, mir, ARMV5TE_LDRSH_RRR, vB, vC, vA, 1);
+ break;
+ case OP_APUT_WIDE:
+ genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 3);
+ break;
+ case OP_APUT:
+ case OP_APUT_OBJECT:
+ genArrayPut(cUnit, mir, ARMV5TE_STR_RRR, vB, vC, vA, 2);
+ break;
+ case OP_APUT_SHORT:
+ case OP_APUT_CHAR:
+ genArrayPut(cUnit, mir, ARMV5TE_STRH_RRR, vB, vC, vA, 1);
+ break;
+ case OP_APUT_BYTE:
+ case OP_APUT_BOOLEAN:
+ genArrayPut(cUnit, mir, ARMV5TE_STRB_RRR, vB, vC, vA, 0);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt31t(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ switch (dalvikOpCode) {
+ case OP_FILL_ARRAY_DATA: {
+ loadConstant(cUnit, r4PC, (int)dvmInterpHandleFillArrayData);
+ loadValue(cUnit, mir->dalvikInsn.vA, r0);
+ loadConstant(cUnit, r1, (mir->dalvikInsn.vB << 1) +
+ (int) (cUnit->method->insns + mir->offset));
+ genExportPC(cUnit, mir, r2, r3 );
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ genZeroCheck(cUnit, r0, mir->offset, NULL);
+ break;
+ }
+ /*
+ * TODO
+ * - Add a 1 to 3-entry per-location cache here to completely
+ * bypass the dvmInterpHandle[Packed/Sparse]Switch call w/ chaining
+ * - Use out-of-line handlers for both of these
+ */
+ case OP_PACKED_SWITCH:
+ case OP_SPARSE_SWITCH: {
+ if (dalvikOpCode == OP_PACKED_SWITCH) {
+ loadConstant(cUnit, r4PC, (int)dvmInterpHandlePackedSwitch);
+ } else {
+ loadConstant(cUnit, r4PC, (int)dvmInterpHandleSparseSwitch);
+ }
+ loadValue(cUnit, mir->dalvikInsn.vA, r1);
+ loadConstant(cUnit, r0, (mir->dalvikInsn.vB << 1) +
+ (int) (cUnit->method->insns + mir->offset));
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+ loadConstant(cUnit, r1, (int)(cUnit->method->insns + mir->offset));
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r2, rGLUE,
+ offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNoChain)
+ >> 2);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, r0, r0, r0);
+ newLIR3(cUnit, ARMV5TE_ADD_RRR, r4PC, r0, r1);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r2);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt35c_3rc(CompilationUnit *cUnit, MIR *mir, BasicBlock *bb,
+ Armv5teLIR *labelList)
+{
+ Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
+ Armv5teLIR *pcrLabel = NULL;
+
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ switch (mir->dalvikInsn.opCode) {
+ /*
+ * calleeMethod = this->clazz->vtable[
+ * method->clazz->pDvmDex->pResMethods[BBBB]->methodIndex
+ * ]
+ */
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_VIRTUAL_RANGE: {
+ int methodIndex =
+ cUnit->method->clazz->pDvmDex->pResMethods[dInsn->vB]->
+ methodIndex;
+
+ if (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r0 now contains this->clazz */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
+ offsetof(Object, clazz) >> 2);
+ /* r1 = &retChainingCell */
+ Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
+ r1, 0);
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+
+ /* r0 now contains this->clazz->vtable */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
+ offsetof(ClassObject, vtable) >> 2);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+ if (methodIndex < 32) {
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, methodIndex);
+ } else {
+ loadConstant(cUnit, r7, methodIndex<<2);
+ newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r7);
+ }
+
+ /*
+ * r0 = calleeMethod,
+ * r1 = &ChainingCell,
+ * r4PC = callsiteDPC,
+ */
+ genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(INVOKE_STATS)
+ gDvmJit.invokeNoOpt++;
+#endif
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+ break;
+ }
+ /*
+ * calleeMethod = method->clazz->super->vtable[method->clazz->pDvmDex
+ * ->pResMethods[BBBB]->methodIndex]
+ */
+ /* TODO - not excersized in RunPerf.jar */
+ 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];
+
+ if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r0 = calleeMethod */
+ loadConstant(cUnit, r0, (int) calleeMethod);
+
+ genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ break;
+ }
+ /* 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];
+
+ if (mir->dalvikInsn.opCode == OP_INVOKE_DIRECT)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r0 = calleeMethod */
+ loadConstant(cUnit, r0, (int) calleeMethod);
+
+ genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ break;
+ }
+ /* 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];
+
+ if (mir->dalvikInsn.opCode == OP_INVOKE_STATIC)
+ genProcessArgsNoRange(cUnit, mir, dInsn,
+ NULL /* no null check */);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn,
+ NULL /* no null check */);
+
+ /* r0 = calleeMethod */
+ loadConstant(cUnit, r0, (int) calleeMethod);
+
+ genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ break;
+ }
+ /*
+ * calleeMethod = dvmFindInterfaceMethodInCache(this->clazz,
+ * BBBB, method, method->clazz->pDvmDex)
+ */
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_INTERFACE_RANGE: {
+ int methodIndex = dInsn->vB;
+
+ if (mir->dalvikInsn.opCode == OP_INVOKE_INTERFACE)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r0 now contains this->clazz */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
+ offsetof(Object, clazz) >> 2);
+
+ /* r1 = BBBB */
+ loadConstant(cUnit, r1, dInsn->vB);
+
+ /* r2 = method (caller) */
+ loadConstant(cUnit, r2, (int) cUnit->method);
+
+ /* r3 = pDvmDex */
+ loadConstant(cUnit, r3, (int) cUnit->method->clazz->pDvmDex);
+
+ loadConstant(cUnit, r7,
+ (intptr_t) dvmFindInterfaceMethodInCache);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r7);
+
+ /* r0 = calleeMethod (returned from dvmFindInterfaceMethodInCache */
+
+ /* r1 = &retChainingCell */
+ Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
+ r1, 0);
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+ /*
+ * r0 = this, r1 = calleeMethod,
+ * r1 = &ChainingCell,
+ * r4PC = callsiteDPC,
+ */
+ genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(INVOKE_STATS)
+ gDvmJit.invokeNoOpt++;
+#endif
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+ break;
+ }
+ /* NOP */
+ case OP_INVOKE_DIRECT_EMPTY: {
+ return false;
+ }
+ case OP_FILLED_NEW_ARRAY:
+ case OP_FILLED_NEW_ARRAY_RANGE: {
+ /* Just let the interpreter deal with these */
+ genInterpSingleStep(cUnit, mir);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt35ms_3rms(CompilationUnit *cUnit, MIR *mir,
+ BasicBlock *bb, Armv5teLIR *labelList)
+{
+ Armv5teLIR *retChainingCell = &labelList[bb->fallThrough->id];
+ Armv5teLIR *pcrLabel = NULL;
+
+ 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 (mir->dalvikInsn.opCode == OP_INVOKE_VIRTUAL_QUICK)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r0 now contains this->clazz */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
+ offsetof(Object, clazz) >> 2);
+ /* r1 = &retChainingCell */
+ Armv5teLIR *addrRetChain = newLIR2(cUnit, ARMV5TE_ADD_PC_REL,
+ r1, 0);
+ /* r4PC = dalvikCallsite */
+ loadConstant(cUnit, r4PC,
+ (int) (cUnit->method->insns + mir->offset));
+
+ /* r0 now contains this->clazz->vtable */
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0,
+ offsetof(ClassObject, vtable) >> 2);
+ addrRetChain->generic.target = (LIR *) retChainingCell;
+
+ if (methodIndex < 32) {
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, r0, methodIndex);
+ } else {
+ loadConstant(cUnit, r7, methodIndex<<2);
+ newLIR3(cUnit, ARMV5TE_LDR_RRR, r0, r0, r7);
+ }
+
+ /*
+ * r0 = calleeMethod,
+ * r1 = &ChainingCell,
+ * r4PC = callsiteDPC,
+ */
+ genDispatchToHandler(cUnit, TEMPLATE_INVOKE_METHOD_NO_OPT);
+#if defined(INVOKE_STATS)
+ gDvmJit.invokeNoOpt++;
+#endif
+ break;
+ }
+ /* 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];
+
+ if (mir->dalvikInsn.opCode == OP_INVOKE_SUPER_QUICK)
+ genProcessArgsNoRange(cUnit, mir, dInsn, &pcrLabel);
+ else
+ genProcessArgsRange(cUnit, mir, dInsn, &pcrLabel);
+
+ /* r0 = calleeMethod */
+ loadConstant(cUnit, r0, (int) calleeMethod);
+
+ genInvokeCommon(cUnit, mir, bb, labelList, pcrLabel,
+ calleeMethod);
+ break;
+ }
+ /* calleeMethod = method->clazz->super->vtable[BBBB] */
+ default:
+ return true;
+ }
+ /* Handle exceptions using the interpreter */
+ genTrap(cUnit, mir->offset, pcrLabel);
+ return false;
+}
+
+/*
+ * NOTE: We assume here that the special native inline routines
+ * are side-effect free. By making this assumption, we can safely
+ * re-execute the routine from the interpreter if it decides it
+ * wants to throw an exception. We still need to EXPORT_PC(), though.
+ */
+static bool handleFmt3inline(CompilationUnit *cUnit, MIR *mir)
+{
+ DecodedInstruction *dInsn = &mir->dalvikInsn;
+ switch( mir->dalvikInsn.opCode) {
+ case OP_EXECUTE_INLINE: {
+ unsigned int i;
+ const InlineOperation* inLineTable = dvmGetInlineOpsTable();
+ int offset = (int) &((InterpState *) NULL)->retval;
+ int operation = dInsn->vB;
+
+ if (!strcmp(inLineTable[operation].classDescriptor,
+ "Ljava/lang/String;") &&
+ !strcmp(inLineTable[operation].methodName,
+ "length") &&
+ !strcmp(inLineTable[operation].methodSignature,
+ "()I")) {
+ return genInlinedStringLength(cUnit,mir);
+ }
+
+ /* Materialize pointer to retval & push */
+ newLIR2(cUnit, ARMV5TE_MOV_RR, r4PC, rGLUE);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, r4PC, offset);
+ /* Push r4 and (just to take up space) r5) */
+ newLIR1(cUnit, ARMV5TE_PUSH, (1<<r4PC | 1<<rFP));
+
+ /* Get code pointer to inline routine */
+ loadConstant(cUnit, r4PC, (int)inLineTable[operation].func);
+
+ /* Export PC */
+ genExportPC(cUnit, mir, r0, r1 );
+
+ /* Load arguments to r0 through r3 as applicable */
+ for (i=0; i < dInsn->vA; i++) {
+ loadValue(cUnit, dInsn->arg[i], i);
+ }
+ /* Call inline routine */
+ newLIR1(cUnit, ARMV5TE_BLX_R, r4PC);
+
+ /* Strip frame */
+ newLIR1(cUnit, ARMV5TE_ADD_SPI7, 2);
+
+ /* Did we throw? If so, redo under interpreter*/
+ genZeroCheck(cUnit, r0, mir->offset, NULL);
+
+ resetRegisterScoreboard(cUnit);
+ break;
+ }
+ default:
+ return true;
+ }
+ return false;
+}
+
+static bool handleFmt51l(CompilationUnit *cUnit, MIR *mir)
+{
+ loadConstant(cUnit, r0, mir->dalvikInsn.vB_wide & 0xFFFFFFFFUL);
+ loadConstant(cUnit, r1, (mir->dalvikInsn.vB_wide>>32) & 0xFFFFFFFFUL);
+ storeValuePair(cUnit, r0, r1, mir->dalvikInsn.vA, r2);
+ return false;
+}
+
+/*****************************************************************************/
+/*
+ * The following are special processing routines that handle transfer of
+ * controls between compiled code and the interpreter. Certain VM states like
+ * Dalvik PC and special-purpose registers are reconstructed here.
+ */
+
+/* Chaining cell for code that may need warmup. */
+static void handleNormalChainingCell(CompilationUnit *cUnit,
+ unsigned int offset)
+{
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
+ offsetof(InterpState, jitToInterpEntries.dvmJitToInterpNormal) >> 2);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r0);
+ addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
+}
+
+/*
+ * Chaining cell for instructions that immediately following already translated
+ * code.
+ */
+static void handleHotChainingCell(CompilationUnit *cUnit,
+ unsigned int offset)
+{
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
+ offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r0);
+ addWordData(cUnit, (int) (cUnit->method->insns + offset), true);
+}
+
+/* Chaining cell for monomorphic method invocations. */
+static void handleInvokeChainingCell(CompilationUnit *cUnit,
+ const Method *callee)
+{
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r0, rGLUE,
+ offsetof(InterpState, jitToInterpEntries.dvmJitToTraceSelect) >> 2);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r0);
+ addWordData(cUnit, (int) (callee->insns), true);
+}
+
+/* Load the Dalvik PC into r0 and jump to the specified target */
+static void handlePCReconstruction(CompilationUnit *cUnit,
+ Armv5teLIR *targetLabel)
+{
+ Armv5teLIR **pcrLabel =
+ (Armv5teLIR **) cUnit->pcReconstructionList.elemList;
+ int numElems = cUnit->pcReconstructionList.numUsed;
+ int i;
+ for (i = 0; i < numElems; i++) {
+ dvmCompilerAppendLIR(cUnit, (LIR *) pcrLabel[i]);
+ /* r0 = dalvik PC */
+ loadConstant(cUnit, r0, pcrLabel[i]->operands[0]);
+ genUnconditionalBranch(cUnit, targetLabel);
+ }
+}
+
+/* Entry function to invoke the backend of the JIT compiler */
+void dvmCompilerMIR2LIR(CompilationUnit *cUnit)
+{
+ /* Used to hold the labels of each block */
+ Armv5teLIR *labelList =
+ dvmCompilerNew(sizeof(Armv5teLIR) * cUnit->numBlocks, true);
+ GrowableList chainingListByType[CHAINING_CELL_LAST];
+ int i;
+
+ /*
+ * Initialize the three chaining lists for generic, post-invoke, and invoke
+ * chains.
+ */
+ for (i = 0; i < CHAINING_CELL_LAST; i++) {
+ dvmInitGrowableList(&chainingListByType[i], 2);
+ }
+
+ BasicBlock **blockList = cUnit->blockList;
+
+ if (cUnit->executionCount) {
+ /*
+ * Reserve 6 bytes at the beginning of the trace
+ * +----------------------------+
+ * | execution count (4 bytes) |
+ * +----------------------------+
+ * | chain cell offset (2 bytes)|
+ * +----------------------------+
+ * ...and then code to increment the execution
+ * count:
+ * mov r0, pc @ move adr of "mov r0,pc" + 4 to r0
+ * sub r0, #10 @ back up to addr of executionCount
+ * ldr r1, [r0]
+ * add r1, #1
+ * str r1, [r0]
+ */
+ newLIR1(cUnit, ARMV5TE_16BIT_DATA, 0);
+ newLIR1(cUnit, ARMV5TE_16BIT_DATA, 0);
+ cUnit->chainCellOffsetLIR =
+ (LIR *) newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
+ cUnit->headerSize = 6;
+ newLIR2(cUnit, ARMV5TE_MOV_RR_HL, r0, rpc & THUMB_REG_MASK);
+ newLIR2(cUnit, ARMV5TE_SUB_RI8, r0, 10);
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, r0, 0);
+ newLIR2(cUnit, ARMV5TE_ADD_RI8, r1, 1);
+ newLIR3(cUnit, ARMV5TE_STR_RRI5, r1, r0, 0);
+ } else {
+ /* Just reserve 2 bytes for the chain cell offset */
+ cUnit->chainCellOffsetLIR =
+ (LIR *) newLIR1(cUnit, ARMV5TE_16BIT_DATA, CHAIN_CELL_OFFSET_TAG);
+ cUnit->headerSize = 2;
+ }
+
+ /* Handle the content in each basic block */
+ for (i = 0; i < cUnit->numBlocks; i++) {
+ blockList[i]->visited = true;
+ MIR *mir;
+
+ labelList[i].operands[0] = blockList[i]->startOffset;
+
+ if (blockList[i]->blockType >= CHAINING_CELL_LAST) {
+ /*
+ * Append the label pseudo LIR first. Chaining cells will be handled
+ * separately afterwards.
+ */
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[i]);
+ }
+
+ if (blockList[i]->blockType == DALVIK_BYTECODE) {
+ labelList[i].opCode = ARMV5TE_PSEUDO_NORMAL_BLOCK_LABEL;
+ /* Reset the register state */
+ resetRegisterScoreboard(cUnit);
+ } else {
+ switch (blockList[i]->blockType) {
+ case CHAINING_CELL_NORMAL:
+ labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_NORMAL;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[CHAINING_CELL_NORMAL], (void *) i);
+ break;
+ case CHAINING_CELL_INVOKE:
+ labelList[i].opCode = ARMV5TE_PSEUDO_CHAINING_CELL_INVOKE;
+ labelList[i].operands[0] =
+ (int) blockList[i]->containingMethod;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[CHAINING_CELL_INVOKE], (void *) i);
+ break;
+ case CHAINING_CELL_HOT:
+ labelList[i].opCode =
+ ARMV5TE_PSEUDO_CHAINING_CELL_HOT;
+ /* handle the codegen later */
+ dvmInsertGrowableList(
+ &chainingListByType[CHAINING_CELL_HOT],
+ (void *) i);
+ break;
+ case PC_RECONSTRUCTION:
+ /* Make sure exception handling block is next */
+ labelList[i].opCode =
+ ARMV5TE_PSEUDO_PC_RECONSTRUCTION_BLOCK_LABEL;
+ assert (i == cUnit->numBlocks - 2);
+ handlePCReconstruction(cUnit, &labelList[i+1]);
+ break;
+ case EXCEPTION_HANDLING:
+ labelList[i].opCode = ARMV5TE_PSEUDO_EH_BLOCK_LABEL;
+ if (cUnit->pcReconstructionList.numUsed) {
+ newLIR3(cUnit, ARMV5TE_LDR_RRI5, r1, rGLUE,
+ offsetof(InterpState,
+ jitToInterpEntries.dvmJitToInterpPunt)
+ >> 2);
+ newLIR1(cUnit, ARMV5TE_BLX_R, r1);
+ }
+ break;
+ default:
+ break;
+ }
+ continue;
+ }
+
+ Armv5teLIR *headLIR = NULL;
+
+ for (mir = blockList[i]->firstMIRInsn; mir; mir = mir->next) {
+ OpCode dalvikOpCode = mir->dalvikInsn.opCode;
+ InstructionFormat dalvikFormat =
+ dexGetInstrFormat(gDvm.instrFormat, dalvikOpCode);
+ Armv5teLIR *boundaryLIR =
+ newLIR2(cUnit, ARMV5TE_PSEUDO_DALVIK_BYTECODE_BOUNDARY,
+ mir->offset,dalvikOpCode);
+ /* Remember the first LIR for this block */
+ if (headLIR == NULL) {
+ headLIR = boundaryLIR;
+ }
+ bool notHandled;
+ /*
+ * Debugging: screen the opcode first to see if it is in the
+ * do[-not]-compile list
+ */
+ bool singleStepMe =
+ gDvmJit.includeSelectedOp !=
+ ((gDvmJit.opList[dalvikOpCode >> 3] &
+ (1 << (dalvikOpCode & 0x7))) !=
+ 0);
+ if (singleStepMe || cUnit->allSingleStep) {
+ notHandled = false;
+ genInterpSingleStep(cUnit, mir);
+ } else {
+ opcodeCoverage[dalvikOpCode]++;
+ switch (dalvikFormat) {
+ case kFmt10t:
+ case kFmt20t:
+ case kFmt30t:
+ notHandled = handleFmt10t_Fmt20t_Fmt30t(cUnit,
+ mir, blockList[i], labelList);
+ break;
+ case kFmt10x:
+ notHandled = handleFmt10x(cUnit, mir);
+ break;
+ case kFmt11n:
+ case kFmt31i:
+ notHandled = handleFmt11n_Fmt31i(cUnit, mir);
+ break;
+ case kFmt11x:
+ notHandled = handleFmt11x(cUnit, mir);
+ break;
+ case kFmt12x:
+ notHandled = handleFmt12x(cUnit, mir);
+ break;
+ case kFmt20bc:
+ notHandled = handleFmt20bc(cUnit, mir);
+ break;
+ case kFmt21c:
+ case kFmt31c:
+ notHandled = handleFmt21c_Fmt31c(cUnit, mir);
+ break;
+ case kFmt21h:
+ notHandled = handleFmt21h(cUnit, mir);
+ break;
+ case kFmt21s:
+ notHandled = handleFmt21s(cUnit, mir);
+ break;
+ case kFmt21t:
+ notHandled = handleFmt21t(cUnit, mir, blockList[i],
+ labelList);
+ break;
+ case kFmt22b:
+ case kFmt22s:
+ notHandled = handleFmt22b_Fmt22s(cUnit, mir);
+ break;
+ case kFmt22c:
+ notHandled = handleFmt22c(cUnit, mir);
+ break;
+ case kFmt22cs:
+ notHandled = handleFmt22cs(cUnit, mir);
+ break;
+ case kFmt22t:
+ notHandled = handleFmt22t(cUnit, mir, blockList[i],
+ labelList);
+ break;
+ case kFmt22x:
+ case kFmt32x:
+ notHandled = handleFmt22x_Fmt32x(cUnit, mir);
+ break;
+ case kFmt23x:
+ notHandled = handleFmt23x(cUnit, mir);
+ break;
+ case kFmt31t:
+ notHandled = handleFmt31t(cUnit, mir);
+ break;
+ case kFmt3rc:
+ case kFmt35c:
+ notHandled = handleFmt35c_3rc(cUnit, mir, blockList[i],
+ labelList);
+ break;
+ case kFmt3rms:
+ case kFmt35ms:
+ notHandled = handleFmt35ms_3rms(cUnit, mir,blockList[i],
+ labelList);
+ break;
+ case kFmt3inline:
+ notHandled = handleFmt3inline(cUnit, mir);
+ break;
+ case kFmt51l:
+ notHandled = handleFmt51l(cUnit, mir);
+ break;
+ default:
+ notHandled = true;
+ break;
+ }
+ }
+ if (notHandled) {
+ LOGE("%#06x: Opcode 0x%x (%s) / Fmt %d not handled\n",
+ mir->offset,
+ dalvikOpCode, getOpcodeName(dalvikOpCode),
+ dalvikFormat);
+ dvmAbort();
+ break;
+ }
+ }
+
+ /* Eliminate redundant loads/stores and delay stores into later slots */
+ dvmCompilerApplyLocalOptimizations(cUnit, (LIR *) headLIR,
+ cUnit->lastLIRInsn);
+ /*
+ * Check if the block is terminated due to trace length constraint -
+ * insert an unconditional branch to the chaining cell.
+ */
+ if (blockList[i]->needFallThroughBranch) {
+ genUnconditionalBranch(cUnit,
+ &labelList[blockList[i]->fallThrough->id]);
+ }
+
+ }
+
+ /* Handle the chaining cells in predefined order */
+ for (i = 0; i < CHAINING_CELL_LAST; i++) {
+ size_t j;
+ int *blockIdList = (int *) chainingListByType[i].elemList;
+
+ cUnit->numChainingCells[i] = chainingListByType[i].numUsed;
+
+ /* No chaining cells of this type */
+ if (cUnit->numChainingCells[i] == 0)
+ continue;
+
+ /* Record the first LIR for a new type of chaining cell */
+ cUnit->firstChainingLIR[i] = (LIR *) &labelList[blockIdList[0]];
+
+ for (j = 0; j < chainingListByType[i].numUsed; j++) {
+ int blockId = blockIdList[j];
+
+ /* Align this chaining cell first */
+ newLIR0(cUnit, ARMV5TE_PSEUDO_ALIGN4);
+
+ /* Insert the pseudo chaining instruction */
+ dvmCompilerAppendLIR(cUnit, (LIR *) &labelList[blockId]);
+
+
+ switch (blockList[blockId]->blockType) {
+ case CHAINING_CELL_NORMAL:
+ handleNormalChainingCell(cUnit,
+ blockList[blockId]->startOffset);
+ break;
+ case CHAINING_CELL_INVOKE:
+ handleInvokeChainingCell(cUnit,
+ blockList[blockId]->containingMethod);
+ break;
+ case CHAINING_CELL_HOT:
+ handleHotChainingCell(cUnit,
+ blockList[blockId]->startOffset);
+ break;
+ default:
+ dvmAbort();
+ break;
+ }
+ }
+ }
+
+ dvmCompilerApplyGlobalOptimizations(cUnit);
+}
+
+/* Accept the work and start compiling */
+void *dvmCompilerDoWork(CompilerWorkOrder *work)
+{
+ void *res;
+
+ if (gDvmJit.codeCacheFull) {
+ return NULL;
+ }
+
+ switch (work->kind) {
+ case kWorkOrderMethod:
+ res = dvmCompileMethod(work->info);
+ break;
+ case kWorkOrderTrace:
+ /* Start compilation with maximally allowed trace length */
+ res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN);
+ break;
+ default:
+ res = NULL;
+ dvmAbort();
+ }
+ return res;
+}
+
+/* Architecture-specific initializations and checks go here */
+bool dvmCompilerArchInit(void)
+{
+ /* First, declare dvmCompiler_TEMPLATE_XXX for each template */
+#define JIT_TEMPLATE(X) extern void dvmCompiler_TEMPLATE_##X();
+#include "../../template/armv5te/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+ int i = 0;
+ extern void dvmCompilerTemplateStart(void);
+
+ /*
+ * Then, populate the templateEntryOffsets array with the offsets from the
+ * the dvmCompilerTemplateStart symbol for each template.
+ */
+#define JIT_TEMPLATE(X) templateEntryOffsets[i++] = \
+ (intptr_t) dvmCompiler_TEMPLATE_##X - (intptr_t) dvmCompilerTemplateStart;
+#include "../../template/armv5te/TemplateOpList.h"
+#undef JIT_TEMPLATE
+
+ /* Codegen-specific assumptions */
+ assert(offsetof(ClassObject, vtable) < 128 &&
+ (offsetof(ClassObject, vtable) & 0x3) == 0);
+ assert(offsetof(ArrayObject, length) < 128 &&
+ (offsetof(ArrayObject, length) & 0x3) == 0);
+ assert(offsetof(ArrayObject, contents) < 256);
+
+ /* Up to 5 args are pushed on top of FP - sizeofStackSaveArea */
+ assert(sizeof(StackSaveArea) < 236);
+
+ /*
+ * EA is calculated by doing "Rn + imm5 << 2", and there are 5 entry points
+ * that codegen may access, make sure that the offset from the top of the
+ * struct is less than 108.
+ */
+ assert(offsetof(InterpState, jitToInterpEntries) < 108);
+ return true;
+}
+
+/* Architectural-specific debugging helpers go here */
+void dvmCompilerArchDump(void)
+{
+ /* Print compiled opcode in this VM instance */
+ int i, start, streak;
+ char buf[1024];
+
+ streak = i = 0;
+ buf[0] = 0;
+ while (opcodeCoverage[i] == 0 && i < 256) {
+ i++;
+ }
+ if (i == 256) {
+ return;
+ }
+ for (start = i++, streak = 1; i < 256; i++) {
+ if (opcodeCoverage[i]) {
+ streak++;
+ } else {
+ if (streak == 1) {
+ sprintf(buf+strlen(buf), "%x,", start);
+ } else {
+ sprintf(buf+strlen(buf), "%x-%x,", start, start + streak - 1);
+ }
+ streak = 0;
+ while (opcodeCoverage[i] == 0 && i < 256) {
+ i++;
+ }
+ if (i < 256) {
+ streak = 1;
+ start = i;
+ }
+ }
+ }
+ if (streak) {
+ if (streak == 1) {
+ sprintf(buf+strlen(buf), "%x", start);
+ } else {
+ sprintf(buf+strlen(buf), "%x-%x", start, start + streak - 1);
+ }
+ }
+ if (strlen(buf)) {
+ LOGD("dalvik.vm.jit.op = %s", buf);
+ }
+}
+
+/*
+ * Exported version of loadValueAddress
+ * TODO: revisit source file structure
+ */
+void dvmCompilerLoadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest)
+{
+ loadValueAddress(cUnit, vSrc, rDest);
+}
+
+/*
+ * Exported version of genDispatchToHandler
+ * TODO: revisit source file structure
+ */
+void dvmCompilerGenDispatchToHandler(CompilationUnit *cUnit,
+ TemplateOpCode opCode)
+{
+ genDispatchToHandler(cUnit, opCode);
+}
+
+/*
+ * Exported version of loadValue
+ * TODO: revisit source file structure
+ */
+void dvmCompilerLoadValue(CompilationUnit *cUnit, int vSrc, int rDest)
+{
+ loadValue(cUnit, vSrc, rDest);
+}
+
+/*
+ * Exported version of storeValue
+ * TODO: revisit source file structure
+ */
+void dvmCompilerStoreValue(CompilationUnit *cUnit, int rSrc, int vDest,
+ int rScratch)
+{
+ storeValue(cUnit, rSrc, vDest, rScratch);
+}
diff --git a/vm/compiler/codegen/armv5te/Codegen.h b/vm/compiler/codegen/armv5te/Codegen.h
new file mode 100644
index 0000000..f156e60
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/Codegen.h
@@ -0,0 +1,36 @@
+/*
+ * 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 "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+#include "Armv5teLIR.h"
+
+#ifndef _DALVIK_VM_COMPILER_CODEGEN_CODEGEN_H
+#define _DALVIK_VM_COMPILER_CODEGEN_CODEGEN_H
+
+bool dvmCompilerGenConversionPortable(CompilationUnit *cUnit, MIR *mir);
+bool dvmCompilerGenArithOpFloatPortable(CompilationUnit *cUnit, MIR *mir,
+ int vDest, int vSrc1, int vSrc2);
+bool dvmCompilerGenArithOpDoublePortable(CompilationUnit *cUnit, MIR *mir,
+ int vDest, int vSrc1, int vSrc2);
+void dvmCompilerLoadValueAddress(CompilationUnit *cUnit, int vSrc, int rDest);
+void dvmCompilerGenDispatchToHandler(CompilationUnit *cUnit,
+ TemplateOpCode opCode);
+void dvmCompilerLoadValue(CompilationUnit *cUnit, int vSrc, int rDest);
+void dvmCompilerStoreValue(CompilationUnit *cUnit, int rSrc, int vDest,
+ int rScratch);
+
+#endif /* _DALVIK_VM_COMPILER_CODEGEN_CODEGEN_H */
diff --git a/vm/compiler/codegen/armv5te/FpCodegen-armv5te-vfp.c b/vm/compiler/codegen/armv5te/FpCodegen-armv5te-vfp.c
new file mode 100644
index 0000000..a2dc3bf
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/FpCodegen-armv5te-vfp.c
@@ -0,0 +1,174 @@
+/*
+ * 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 "Dalvik.h"
+#include "Armv5teLIR.h"
+#include "Codegen.h"
+
+bool dvmCompilerGenArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ TemplateOpCode opCode;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_FLOAT_2ADDR:
+ case OP_ADD_FLOAT:
+ opCode = TEMPLATE_ADD_FLOAT_VFP;
+ break;
+ case OP_SUB_FLOAT_2ADDR:
+ case OP_SUB_FLOAT:
+ opCode = TEMPLATE_SUB_FLOAT_VFP;
+ case OP_DIV_FLOAT_2ADDR:
+ case OP_DIV_FLOAT:
+ opCode = TEMPLATE_DIV_FLOAT_VFP;
+ break;
+ case OP_MUL_FLOAT_2ADDR:
+ case OP_MUL_FLOAT:
+ opCode = TEMPLATE_MUL_FLOAT_VFP;
+ break;
+ case OP_REM_FLOAT_2ADDR:
+ case OP_REM_FLOAT:
+ case OP_NEG_FLOAT: {
+ return dvmCompilerGenArithOpFloatPortable(cUnit, mir, vDest,
+ vSrc1, vSrc2);
+ }
+ default:
+ return true;
+ }
+ dvmCompilerLoadValueAddress(cUnit, vDest, r0);
+ dvmCompilerLoadValueAddress(cUnit, vSrc1, r1);
+ dvmCompilerLoadValueAddress(cUnit, vSrc2, r2);
+ dvmCompilerGenDispatchToHandler(cUnit, opCode);
+ return false;
+}
+
+bool dvmCompilerGenArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ TemplateOpCode opCode;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_ADD_DOUBLE_2ADDR:
+ case OP_ADD_DOUBLE:
+ opCode = TEMPLATE_ADD_DOUBLE_VFP;
+ break;
+ case OP_SUB_DOUBLE_2ADDR:
+ case OP_SUB_DOUBLE:
+ opCode = TEMPLATE_SUB_DOUBLE_VFP;
+ break;
+ case OP_DIV_DOUBLE_2ADDR:
+ case OP_DIV_DOUBLE:
+ opCode = TEMPLATE_DIV_DOUBLE_VFP;
+ break;
+ case OP_MUL_DOUBLE_2ADDR:
+ case OP_MUL_DOUBLE:
+ opCode = TEMPLATE_MUL_DOUBLE_VFP;
+ break;
+ case OP_REM_DOUBLE_2ADDR:
+ case OP_REM_DOUBLE:
+ case OP_NEG_DOUBLE: {
+ return dvmCompilerGenArithOpDoublePortable(cUnit, mir, vDest,
+ vSrc1, vSrc2);
+ }
+ default:
+ return true;
+ }
+ dvmCompilerLoadValueAddress(cUnit, vDest, r0);
+ dvmCompilerLoadValueAddress(cUnit, vSrc1, r1);
+ dvmCompilerLoadValueAddress(cUnit, vSrc2, r2);
+ dvmCompilerGenDispatchToHandler(cUnit, opCode);
+ return false;
+}
+
+bool dvmCompilerGenConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ OpCode opCode = mir->dalvikInsn.opCode;
+ int vSrc1Dest = mir->dalvikInsn.vA;
+ int vSrc2 = mir->dalvikInsn.vB;
+ TemplateOpCode template;
+
+ switch (opCode) {
+ case OP_INT_TO_FLOAT:
+ template = TEMPLATE_INT_TO_FLOAT_VFP;
+ break;
+ case OP_FLOAT_TO_INT:
+ template = TEMPLATE_FLOAT_TO_INT_VFP;
+ break;
+ case OP_DOUBLE_TO_FLOAT:
+ template = TEMPLATE_DOUBLE_TO_FLOAT_VFP;
+ break;
+ case OP_FLOAT_TO_DOUBLE:
+ template = TEMPLATE_FLOAT_TO_DOUBLE_VFP;
+ break;
+ case OP_INT_TO_DOUBLE:
+ template = TEMPLATE_INT_TO_DOUBLE_VFP;
+ break;
+ case OP_DOUBLE_TO_INT:
+ template = TEMPLATE_DOUBLE_TO_INT_VFP;
+ break;
+ case OP_FLOAT_TO_LONG:
+ case OP_LONG_TO_FLOAT:
+ case OP_DOUBLE_TO_LONG:
+ case OP_LONG_TO_DOUBLE:
+ return dvmCompilerGenConversionPortable(cUnit, mir);
+ default:
+ return true;
+ }
+ dvmCompilerLoadValueAddress(cUnit, vSrc1Dest, r0);
+ dvmCompilerLoadValueAddress(cUnit, vSrc2, r1);
+ dvmCompilerGenDispatchToHandler(cUnit, template);
+ return false;
+}
+
+bool dvmCompilerGenCmpX(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ TemplateOpCode template;
+
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch(mir->dalvikInsn.opCode) {
+ case OP_CMPL_FLOAT:
+ template = TEMPLATE_CMPL_FLOAT_VFP;
+ break;
+ case OP_CMPG_FLOAT:
+ template = TEMPLATE_CMPG_FLOAT_VFP;
+ break;
+ case OP_CMPL_DOUBLE:
+ template = TEMPLATE_CMPL_DOUBLE_VFP;
+ break;
+ case OP_CMPG_DOUBLE:
+ template = TEMPLATE_CMPG_DOUBLE_VFP;
+ break;
+ default:
+ return true;
+ }
+ dvmCompilerLoadValueAddress(cUnit, vSrc1, r0);
+ dvmCompilerLoadValueAddress(cUnit, vSrc2, r1);
+ dvmCompilerGenDispatchToHandler(cUnit, template);
+ dvmCompilerStoreValue(cUnit, r0, vDest, r1);
+ return false;
+}
diff --git a/vm/compiler/codegen/armv5te/FpCodegen-armv5te.c b/vm/compiler/codegen/armv5te/FpCodegen-armv5te.c
new file mode 100644
index 0000000..b69824d
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/FpCodegen-armv5te.c
@@ -0,0 +1,74 @@
+/*
+ * 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 "Dalvik.h"
+#include "Armv5teLIR.h"
+#include "Codegen.h"
+
+bool dvmCompilerGenConversion(CompilationUnit *cUnit, MIR *mir)
+{
+ return dvmCompilerGenConversionPortable(cUnit, mir);
+}
+
+bool dvmCompilerGenArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ return dvmCompilerGenArithOpFloatPortable(cUnit, mir, vDest, vSrc1, vSrc2);
+}
+
+bool dvmCompilerGenArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ return dvmCompilerGenArithOpDoublePortable(cUnit, mir, vDest, vSrc1, vSrc2);
+}
+
+bool dvmCompilerGenCmpX(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2)
+{
+ /*
+ * Don't attempt to optimize register usage since these opcodes call out to
+ * the handlers.
+ */
+ switch (mir->dalvikInsn.opCode) {
+ case OP_CMPL_FLOAT:
+ dvmCompilerLoadValue(cUnit, vSrc1, r0);
+ dvmCompilerLoadValue(cUnit, vSrc2, r1);
+ dvmCompilerGenDispatchToHandler(cUnit, TEMPLATE_CMPL_FLOAT);
+ dvmCompilerStoreValue(cUnit, r0, vDest, r1);
+ break;
+ case OP_CMPG_FLOAT:
+ dvmCompilerLoadValue(cUnit, vSrc1, r0);
+ dvmCompilerLoadValue(cUnit, vSrc2, r1);
+ dvmCompilerGenDispatchToHandler(cUnit, TEMPLATE_CMPG_FLOAT);
+ dvmCompilerStoreValue(cUnit, r0, vDest, r1);
+ break;
+ case OP_CMPL_DOUBLE:
+ dvmCompilerLoadValueAddress(cUnit, vSrc1, r0);
+ dvmCompilerLoadValueAddress(cUnit, vSrc2, r1);
+ dvmCompilerGenDispatchToHandler(cUnit, TEMPLATE_CMPL_DOUBLE);
+ dvmCompilerStoreValue(cUnit, r0, vDest, r1);
+ break;
+ case OP_CMPG_DOUBLE:
+ dvmCompilerLoadValueAddress(cUnit, vSrc1, r0);
+ dvmCompilerLoadValueAddress(cUnit, vSrc2, r1);
+ dvmCompilerGenDispatchToHandler(cUnit, TEMPLATE_CMPG_DOUBLE);
+ dvmCompilerStoreValue(cUnit, r0, vDest, r1);
+ break;
+ default:
+ return true;
+ }
+ return false;
+}
diff --git a/vm/compiler/codegen/armv5te/FpCodegen.h b/vm/compiler/codegen/armv5te/FpCodegen.h
new file mode 100644
index 0000000..72625b5
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/FpCodegen.h
@@ -0,0 +1,32 @@
+/*
+ * 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 "Dalvik.h"
+#include "compiler/CompilerInternals.h"
+
+#ifndef _DALVIK_VM_COMPILER_CODEGEN_FPCODEGEN_H
+#define _DALVIK_VM_COMPILER_CODEGEN_FPCODEGEN_H
+
+bool dvmCompilerGenConversion(CompilationUnit *cUnit, MIR *mir);
+bool dvmCompilerGenArithOpFloat(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2);
+bool dvmCompilerGenArithOpDouble(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2);
+bool dvmCompilerGenCmpX(CompilationUnit *cUnit, MIR *mir, int vDest,
+ int vSrc1, int vSrc2);
+
+
+#endif /* _DALVIK_VM_COMPILER_CODEGEN_FPCODEGEN_H */
diff --git a/vm/compiler/codegen/armv5te/GlobalOptimizations.c b/vm/compiler/codegen/armv5te/GlobalOptimizations.c
new file mode 100644
index 0000000..2b8ec6f
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/GlobalOptimizations.c
@@ -0,0 +1,62 @@
+/*
+ * 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 "Dalvik.h"
+#include "vm/compiler/CompilerInternals.h"
+#include "Armv5teLIR.h"
+
+/*
+ * Identify unconditional branches that jump to the immediate successor of the
+ * branch itself.
+ */
+static void applyRedundantBranchElimination(CompilationUnit *cUnit)
+{
+ Armv5teLIR *thisLIR;
+
+ for (thisLIR = (Armv5teLIR *) cUnit->firstLIRInsn;
+ thisLIR != (Armv5teLIR *) cUnit->lastLIRInsn;
+ thisLIR = NEXT_LIR(thisLIR)) {
+
+ /* Branch to the next instruction */
+ if (thisLIR->opCode == ARMV5TE_B_UNCOND) {
+ Armv5teLIR *nextLIR = thisLIR;
+
+ while (true) {
+ nextLIR = NEXT_LIR(nextLIR);
+
+ /*
+ * Is the branch target the next instruction?
+ */
+ if (nextLIR == (Armv5teLIR *) thisLIR->generic.target) {
+ thisLIR->isNop = true;
+ break;
+ }
+
+ /*
+ * Found real useful stuff between the branch and the target
+ */
+ if (!isPseudoOpCode(nextLIR->opCode) ||
+ nextLIR->opCode == ARMV5TE_PSEUDO_ALIGN4)
+ break;
+ }
+ }
+ }
+}
+
+void dvmCompilerApplyGlobalOptimizations(CompilationUnit *cUnit)
+{
+ applyRedundantBranchElimination(cUnit);
+}
diff --git a/vm/compiler/codegen/armv5te/LocalOptimizations.c b/vm/compiler/codegen/armv5te/LocalOptimizations.c
new file mode 100644
index 0000000..1ce91af
--- /dev/null
+++ b/vm/compiler/codegen/armv5te/LocalOptimizations.c
@@ -0,0 +1,139 @@
+/*
+ * 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 "Dalvik.h"
+#include "vm/compiler/CompilerInternals.h"
+#include "Armv5teLIR.h"
+
+/*
+ * Perform a pass of top-down walk to
+ * 1) Eliminate redundant loads and stores
+ * 2) Sink stores to latest possible slot
+ */
+static void applyLoadStoreElimination(CompilationUnit *cUnit,
+ Armv5teLIR *headLIR,
+ Armv5teLIR *tailLIR)
+{
+ Armv5teLIR *thisLIR;
+
+ cUnit->optRound++;
+ for (thisLIR = headLIR;
+ thisLIR != tailLIR;
+ thisLIR = NEXT_LIR(thisLIR)) {
+ /* Skip newly added instructions */
+ if (thisLIR->age >= cUnit->optRound) {
+ continue;
+ }
+ if (thisLIR->opCode == ARMV5TE_STR_RRI5 &&
+ thisLIR->operands[1] == rFP) {
+ int dRegId = thisLIR->operands[2];
+ int nativeRegId = thisLIR->operands[0];
+ Armv5teLIR *checkLIR;
+ int sinkDistance = 0;
+
+ for (checkLIR = NEXT_LIR(thisLIR);
+ checkLIR != tailLIR;
+ checkLIR = NEXT_LIR(checkLIR)) {
+
+ /* Check if a Dalvik register load is redundant */
+ if (checkLIR->opCode == ARMV5TE_LDR_RRI5 &&
+ checkLIR->operands[1] == rFP &&
+ checkLIR->operands[2] == dRegId) {
+ /* Insert a move to replace the load */
+ if (checkLIR->operands[0] != nativeRegId) {
+ Armv5teLIR *moveLIR =
+ dvmCompilerNew(sizeof(Armv5teLIR), true);
+ moveLIR->opCode = ARMV5TE_MOV_RR;
+ moveLIR->operands[0] = checkLIR->operands[0];
+ moveLIR->operands[1] = nativeRegId;
+ /*
+ * Insertion is guaranteed to succeed since checkLIR
+ * is never the first LIR on the list
+ */
+ dvmCompilerInsertLIRBefore((LIR *) checkLIR,
+ (LIR *) moveLIR);
+ }
+ checkLIR->isNop = true;
+ continue;
+
+ /* Found a true output dependency - nuke the previous store */
+ } else if (checkLIR->opCode == ARMV5TE_STR_RRI5 &&
+ checkLIR->operands[1] == rFP &&
+ checkLIR->operands[2] == dRegId) {
+ thisLIR->isNop = true;
+ break;
+ /* Find out the latest slot that the store can be sunk into */
+ } else {
+ bool stopHere = false;
+
+ /* Last instruction reached */
+ stopHere |= checkLIR->generic.next == NULL;
+
+ /* Store data is clobbered */
+ stopHere |= (EncodingMap[checkLIR->opCode].flags &
+ CLOBBER_DEST) != 0 &&
+ checkLIR->operands[0] == nativeRegId;
+ /*
+ * Conservatively assume there is a memory dependency
+ * for st/ld multiples and reg+reg address mode
+ */
+ stopHere |= checkLIR->opCode == ARMV5TE_STMIA ||
+ checkLIR->opCode == ARMV5TE_LDMIA ||
+ checkLIR->opCode == ARMV5TE_STR_RRR ||
+ checkLIR->opCode == ARMV5TE_LDR_RRR;
+
+ stopHere |= (EncodingMap[checkLIR->opCode].flags &
+ IS_BRANCH) != 0;
+
+ /* Found a new place to put the store - move it here */
+ if (stopHere == true) {
+
+ /* The store can be sunk for at least one cycle */
+ if (sinkDistance != 0) {
+ Armv5teLIR *newStoreLIR =
+ dvmCompilerNew(sizeof(Armv5teLIR), true);
+ *newStoreLIR = *thisLIR;
+ newStoreLIR->age = cUnit->optRound;
+ /*
+ * Insertion is guaranteed to succeed since checkLIR
+ * is never the first LIR on the list
+ */
+ dvmCompilerInsertLIRBefore((LIR *) checkLIR,
+ (LIR *) newStoreLIR);
+ thisLIR->isNop = true;
+ }
+ break;
+ }
+
+ /*
+ * Saw a real instruction that the store can be sunk after
+ */
+ if (!isPseudoOpCode(checkLIR->opCode)) {
+ sinkDistance++;
+ }
+ }
+ }
+ }
+ }
+}
+
+void dvmCompilerApplyLocalOptimizations(CompilationUnit *cUnit, LIR *headLIR,
+ LIR *tailLIR)
+{
+ applyLoadStoreElimination(cUnit,
+ (Armv5teLIR *) headLIR,
+ (Armv5teLIR *) tailLIR);
+}
diff --git a/vm/compiler/template/Makefile-template b/vm/compiler/template/Makefile-template
new file mode 100644
index 0000000..9203183
--- /dev/null
+++ b/vm/compiler/template/Makefile-template
@@ -0,0 +1,49 @@
+# 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.
+
+#
+# Makefile for the Dalvik modular interpreter. This is not currently
+# integrated into the build system.
+#
+
+SHELL := /bin/sh
+
+# Build system has TARGET_ARCH=arm, but we need the exact architecture.
+# The base assumption for an ARM platform is ARMv5TE, but we may want to
+# support older ARMv4 devices, or use special features from ARMv6 or VFP.
+# The simulator build is "desktop".
+#
+# To generate sources for all targets:
+# for arch in desktop armv5te; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
+#
+#TARGET_ARCH_EXT := armv5te
+
+OUTPUT_DIR := out
+
+# Accumulate all possible dependencies for the generated files in a very
+# conservative fashion. If it's not one of the generated files in "out",
+# assume it's a dependency.
+SOURCE_DEPS := \
+ $(shell find . -path ./$(OUTPUT_DIR) -prune -o -type f -print)
+
+# Source files generated by the script. There's always one C and one
+# assembly file, though in practice one or the other could be empty.
+GEN_SOURCES := \
+ $(OUTPUT_DIR)/CompilerTemplateAsm-$(TARGET_ARCH_EXT).S
+
+target: $(GEN_SOURCES)
+
+$(GEN_SOURCES): $(SOURCE_DEPS)
+ @mkdir -p out
+ ./gen-template.py $(TARGET_ARCH_EXT) $(OUTPUT_DIR)
diff --git a/vm/compiler/template/README.txt b/vm/compiler/template/README.txt
new file mode 100644
index 0000000..fced412
--- /dev/null
+++ b/vm/compiler/template/README.txt
@@ -0,0 +1 @@
+See README.txt under dalvik/vm/mterp for details.
diff --git a/vm/compiler/template/armv5te/TEMPLATE_ADD_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_ADD_DOUBLE_VFP.S
new file mode 100644
index 0000000..7b4fa01
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_ADD_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinopWide.S" {"instr":"faddd d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_ADD_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_ADD_FLOAT_VFP.S
new file mode 100644
index 0000000..6e8077c
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_ADD_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinop.S" {"instr":"fadds s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPG_DOUBLE.S b/vm/compiler/template/armv5te/TEMPLATE_CMPG_DOUBLE.S
new file mode 100644
index 0000000..f18f6d3
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPG_DOUBLE.S
@@ -0,0 +1 @@
+%include "armv5te/TEMPLATE_CMPL_DOUBLE.S" { "naninst":"mov r0, #1" }
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPG_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_CMPG_DOUBLE_VFP.S
new file mode 100644
index 0000000..3801f49
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPG_DOUBLE_VFP.S
@@ -0,0 +1,34 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ *
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ fldd d0, [r0] @ d0<- vBB
+ fldd d1, [r1] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ mov r0, #1 @ r0<- 1 (default)
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r0<- -1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
+
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPG_FLOAT.S b/vm/compiler/template/armv5te/TEMPLATE_CMPG_FLOAT.S
new file mode 100644
index 0000000..02887e5
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPG_FLOAT.S
@@ -0,0 +1 @@
+%include "armv5te/TEMPLATE_CMPL_FLOAT.S" { "naninst":"mov r0, #1" }
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPG_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_CMPG_FLOAT_VFP.S
new file mode 100644
index 0000000..1faafa1
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPG_FLOAT_VFP.S
@@ -0,0 +1,32 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ flds s0, [r0] @ d0<- vBB
+ flds s1, [r1] @ d1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ mov r0, #1 @ r0<- 1 (default)
+ fmstat @ export status flags
+ 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
new file mode 100644
index 0000000..dfafd2c
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE.S
@@ -0,0 +1,39 @@
+%default { "naninst":"mvn r0, #0" }
+ /*
+ * For the JIT: incoming arguments are pointers to the arguments in r0/r1
+ * result in r0
+ *
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * See OP_CMPL_FLOAT for an explanation.
+ *
+ * For: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+ mov r4, lr @ save return address
+ mov r9, r0 @ save copy of &arg1
+ mov r10, r1 @ save copy of &arg2
+ ldmia r9, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r10, {r2-r3} @ r2/r3<- vCC/vCC+1
+ LDR_PC_LR ".L__aeabi_cdcmple" @ PIC way of "bl __aeabi_cdcmple"
+ bhi .L${opcode}_gt_or_nan @ C set and Z clear, disambiguate
+ mvncc r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0, trumps less than
+ bx r4
+
+ @ Test for NaN with a second comparison. EABI forbids testing bit
+ @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+ @ make the library call.
+.L${opcode}_gt_or_nan:
+ ldmia r10, {r0-r1} @ reverse order
+ ldmia r9, {r2-r3}
+ LDR_PC_LR ".L__aeabi_cdcmple" @ r0<- Z set if eq, C clear if <
+ movcc r0, #1 @ (greater than) r1<- 1
+ bxcc r4
+ $naninst @ r1<- 1 or -1 for NaN
+ bx r4
+
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE_VFP.S
new file mode 100644
index 0000000..7241af1
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_DOUBLE_VFP.S
@@ -0,0 +1,32 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ fldd d0, [r0] @ d0<- vBB
+ fldd d1, [r1] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ mvn r0, #0 @ r0<- -1 (default)
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r0<- 1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
new file mode 100644
index 0000000..31d4cd8
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT.S
@@ -0,0 +1,56 @@
+%default { "naninst":"mvn r0, #0" }
+ /*
+ * For the JIT: incoming arguments in r0, r1
+ * result in r0
+ *
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * The straightforward implementation requires 3 calls to functions
+ * that return a result in r0. We can do it with two calls if our
+ * EABI library supports __aeabi_cfcmple (only one if we want to check
+ * for NaN directly):
+ * check x <= y
+ * if <, return -1
+ * if ==, return 0
+ * check y <= x
+ * if <, return 1
+ * return {-1,1}
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+ mov r4, lr @ save return address
+ mov r9, r0 @ Save copies - we may need to redo
+ mov r10, r1
+ LDR_PC_LR ".L__aeabi_cfcmple" @ cmp <=: C clear if <, Z set if eq
+ bhi .L${opcode}_gt_or_nan @ C set and Z clear, disambiguate
+ mvncc r0, #0 @ (less than) r0<- -1
+ moveq r0, #0 @ (equal) r0<- 0, trumps less than
+ bx r4
+ @ Test for NaN with a second comparison. EABI forbids testing bit
+ @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+ @ make the library call.
+.L${opcode}_gt_or_nan:
+ mov r1, r9 @ reverse order
+ mov r0, r10
+ LDR_PC_LR ".L__aeabi_cfcmple" @ r0<- Z set if eq, C clear if <
+ movcc r0, #1 @ (greater than) r1<- 1
+ bxcc r4
+ $naninst @ r1<- 1 or -1 for NaN
+ bx r4
+
+
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT_VFP.S
new file mode 100644
index 0000000..014f160
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMPL_FLOAT_VFP.S
@@ -0,0 +1,32 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ flds s0, [r0] @ d0<- vBB
+ flds s1, [r1] @ d1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ mvn r0, #0 @ r0<- -1 (default)
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r0<- 1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
new file mode 100644
index 0000000..5f1e16b
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_CMP_LONG.S
@@ -0,0 +1,34 @@
+ /*
+ * Compare two 64-bit values. Puts 0, 1, or -1 into the destination
+ * register based on the results of the comparison.
+ *
+ * We load the full values with LDM, but in practice many values could
+ * be resolved by only looking at the high word. This could be made
+ * faster or slower by splitting the LDM into a pair of LDRs.
+ *
+ * If we just wanted to set condition flags, we could do this:
+ * subs ip, r0, r2
+ * sbcs ip, r1, r3
+ * subeqs ip, r0, r2
+ * Leaving { <0, 0, >0 } in ip. However, we have to set it to a specific
+ * integer value, which we can do with 2 conditional mov/mvn instructions
+ * (set 1, set -1; if they're equal we already have 0 in ip), giving
+ * us a constant 5-cycle path plus a branch at the end to the
+ * instruction epilogue code. The multi-compare approach below needs
+ * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
+ * in the worst case (the 64-bit values are equal).
+ */
+ /* cmp-long vAA, vBB, vCC */
+ cmp r1, r3 @ compare (vBB+1, vCC+1)
+ blt .L${opcode}_less @ signed compare on high part
+ bgt .L${opcode}_greater
+ subs r0, r0, r2 @ r0<- r0 - r2
+ bxeq lr
+ bhi .L${opcode}_greater @ unsigned compare on low part
+.L${opcode}_less:
+ mvn r0, #0 @ r0<- -1
+ bx lr
+.L${opcode}_greater:
+ mov r0, #1 @ r0<- 1
+ bx lr
+
diff --git a/vm/compiler/template/armv5te/TEMPLATE_DIV_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_DIV_DOUBLE_VFP.S
new file mode 100644
index 0000000..796275a
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_DIV_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinopWide.S" {"instr":"fdivd d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_DIV_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_DIV_FLOAT_VFP.S
new file mode 100644
index 0000000..5895b93
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_DIV_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinop.S" {"instr":"fdivs s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S
new file mode 100644
index 0000000..96f50c7
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/funopNarrower.S" {"instr":"fcvtsd s0, d0"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_DOUBLE_TO_INT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_DOUBLE_TO_INT_VFP.S
new file mode 100644
index 0000000..f635383
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_DOUBLE_TO_INT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/funopNarrower.S" {"instr":"ftosizd s0, d0"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S
new file mode 100644
index 0000000..a2d68bd
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/funopWider.S" {"instr":"fcvtds d0, s0"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_FLOAT_TO_INT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_FLOAT_TO_INT_VFP.S
new file mode 100644
index 0000000..bebff43
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_FLOAT_TO_INT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/funop.S" {"instr":"ftosizs s1, s0"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INT_TO_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_INT_TO_DOUBLE_VFP.S
new file mode 100644
index 0000000..0a987ac
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INT_TO_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/funopWider.S" {"instr":"fsitod d0, s0"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INT_TO_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_INT_TO_FLOAT_VFP.S
new file mode 100644
index 0000000..105a4a4
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INT_TO_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/funop.S" {"instr":"fsitos s1, s0"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
new file mode 100644
index 0000000..6994f26
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S
@@ -0,0 +1,54 @@
+ /*
+ * For monomorphic callsite, setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ */
+ @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+ ldrh r7, [r0, #offMethod_registersSize] @ r7<- methodToCall->regsSize
+ ldrh r2, [r0, #offMethod_outsSize] @ r2<- methodToCall->outsSize
+ ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
+ ldr r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+ add r3, r1, #1 @ Thumb addr is odd
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
+ sub r1, r1, r7, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
+ add r12, lr, #2 @ setup the punt-to-interp address
+ sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
+ ldr r8, [r8] @ r3<- suspendCount (int)
+ cmp r10, r9 @ bottom < interpStackEnd?
+ bxlt r12 @ 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
+ str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+ str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+ ldr rPC, [r0, #offMethod_insns] @ rPC<- methodToCall->insns
+
+
+ @ set up newSaveArea
+ str rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+ str r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+ str r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ cmp r8, #0 @ suspendCount != 0
+ bxne r12 @ bail to the interpreter
+ tst r10, #ACC_NATIVE
+ bne .LinvokeNative
+ /*
+ * If we want to punt to the interpreter for native call, swap the bne with
+ * the following
+ * bxne r12
+ */
+
+
+ ldr r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
+
+ @ Update "glue" values for the new method
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ mov rFP, r1 @ fp = newFp
+ 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_NO_OPT.S b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
new file mode 100644
index 0000000..003459d
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S
@@ -0,0 +1,53 @@
+ /*
+ * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
+ * into rPC then jump to dvmJitToInterpNoChain to dispatch the
+ * runtime-resolved callee.
+ */
+ @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+ ldrh r7, [r0, #offMethod_registersSize] @ r7<- methodToCall->regsSize
+ ldrh r2, [r0, #offMethod_outsSize] @ r2<- methodToCall->outsSize
+ ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
+ ldr r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+ add r3, r1, #1 @ Thumb addr is odd
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
+ sub r1, r1, r7, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
+ sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
+ ldr r8, [r8] @ r3<- suspendCount (int)
+ cmp r10, r9 @ bottom < interpStackEnd?
+ bxlt 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
+ str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+ str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+ ldr rPC, [r0, #offMethod_insns] @ rPC<- methodToCall->insns
+
+
+ @ set up newSaveArea
+ str rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+ str r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+ str r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ cmp r8, #0 @ suspendCount != 0
+ bxne lr @ bail to the interpreter
+ tst r10, #ACC_NATIVE
+ bne .LinvokeNative
+ /*
+ * If we want to punt to the interpreter for native call, swap the bne with
+ * the following
+ * bxne lr
+ */
+
+
+ ldr r10, .LdvmJitToInterpNoChain
+ ldr r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
+
+ @ Update "glue" values for the new method
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ mov rFP, r1 @ fp = newFp
+ str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
+
+ @ Start executing the callee
+ mov pc, r10 @ dvmJitToInterpNoChain
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MUL_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_MUL_DOUBLE_VFP.S
new file mode 100644
index 0000000..f9afa21
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MUL_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinopWide.S" {"instr":"fmuld d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MUL_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_MUL_FLOAT_VFP.S
new file mode 100644
index 0000000..0666803
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MUL_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinop.S" {"instr":"fmuls s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_MUL_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_MUL_LONG.S
new file mode 100644
index 0000000..8a9b115
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_MUL_LONG.S
@@ -0,0 +1,28 @@
+ /*
+ * Signed 64-bit integer multiply.
+ *
+ * For JIT: op1 in r0/r1, op2 in r2/r3, return in r0/r1
+ *
+ * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
+ * WX
+ * x YZ
+ * --------
+ * ZW ZX
+ * YW YX
+ *
+ * The low word of the result holds ZX, the high word holds
+ * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
+ * it doesn't fit in the low 64 bits.
+ *
+ * Unlike most ARM math operations, multiply instructions have
+ * restrictions on using the same register more than once (Rd and Rm
+ * cannot be the same).
+ */
+ /* mul-long vAA, vBB, vCC */
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ mov r0,r9
+ mov r1,r10
+ bx lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_RETURN.S b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
new file mode 100644
index 0000000..f0a4623
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_RETURN.S
@@ -0,0 +1,38 @@
+ /*
+ * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
+ * If the stored value in returnAddr
+ * is non-zero, the caller is compiled by the JIT thus return to the
+ * address in the code cache following the invoke instruction. Otherwise
+ * return to the special dvmJitToInterpNoChain entry point.
+ */
+ SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
+ ldr r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+ ldr r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+ ldr rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+ ldr r9, [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+ ldr r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ @ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ cmp r2, #0 @ break frame?
+ beq 1f @ bail to interpreter
+ ldr r0, .LdvmJitToInterpNoChain @ defined in footer.S
+ mov rFP, r10 @ publish new FP
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+ ldr r8, [r8] @ r8<- suspendCount
+
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+ str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
+ add rPC, rPC, #6 @ publish new rPC (advance 6 bytes)
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r8, #0 @ check the suspendCount
+ movne r9, #0 @ clear the chaining cell address
+ cmp r9, #0 @ chaining cell exists?
+ blxne r9 @ jump to the chaining cell
+ mov pc, r0 @ callsite is interpreted
+1:
+ stmia rGLUE, {rPC, rFP} @ SAVE_PC_FP_TO_GLUE()
+ ldr r2, .LdvmMterpStdBail @ defined in footer.S
+ mov r1, #0 @ changeInterp = false
+ mov r0, rGLUE @ Expecting rGLUE in r0
+ blx r2 @ exit the interpreter
diff --git a/vm/compiler/template/armv5te/TEMPLATE_SHL_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_SHL_LONG.S
new file mode 100644
index 0000000..532f8a4
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_SHL_LONG.S
@@ -0,0 +1,15 @@
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shl-long vAA, vBB, vCC */
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ bx lr
diff --git a/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S
new file mode 100644
index 0000000..ca7545a
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_SHR_LONG.S
@@ -0,0 +1,16 @@
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shr-long vAA, vBB, vCC */
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ 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_SUB_DOUBLE_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_SUB_DOUBLE_VFP.S
new file mode 100644
index 0000000..0c3dd4e
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_SUB_DOUBLE_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinopWide.S" {"instr":"fsubd d2, d0, d1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_SUB_FLOAT_VFP.S b/vm/compiler/template/armv5te/TEMPLATE_SUB_FLOAT_VFP.S
new file mode 100644
index 0000000..b7bb5b8
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_SUB_FLOAT_VFP.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/fbinop.S" {"instr":"fsubs s2, s0, s1"}
diff --git a/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S b/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S
new file mode 100644
index 0000000..d7c71d9
--- /dev/null
+++ b/vm/compiler/template/armv5te/TEMPLATE_USHR_LONG.S
@@ -0,0 +1,16 @@
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* ushr-long vAA, vBB, vCC */
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ 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/TemplateOpList.h b/vm/compiler/template/armv5te/TemplateOpList.h
new file mode 100644
index 0000000..f41900e
--- /dev/null
+++ b/vm/compiler/template/armv5te/TemplateOpList.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+/*
+ * Dalvik opcode list that uses additional templates to complete JIT execution.
+ */
+#ifndef JIT_TEMPLATE
+#define JIT_TEMPLATE(X)
+#endif
+
+JIT_TEMPLATE(CMP_LONG)
+JIT_TEMPLATE(RETURN)
+JIT_TEMPLATE(INVOKE_METHOD_NO_OPT)
+JIT_TEMPLATE(INVOKE_METHOD_CHAIN)
+JIT_TEMPLATE(CMPG_DOUBLE)
+JIT_TEMPLATE(CMPL_DOUBLE)
+JIT_TEMPLATE(CMPG_FLOAT)
+JIT_TEMPLATE(CMPL_FLOAT)
+JIT_TEMPLATE(MUL_LONG)
+JIT_TEMPLATE(SHL_LONG)
+JIT_TEMPLATE(SHR_LONG)
+JIT_TEMPLATE(USHR_LONG)
+JIT_TEMPLATE(ADD_FLOAT_VFP)
+JIT_TEMPLATE(SUB_FLOAT_VFP)
+JIT_TEMPLATE(MUL_FLOAT_VFP)
+JIT_TEMPLATE(DIV_FLOAT_VFP)
+JIT_TEMPLATE(ADD_DOUBLE_VFP)
+JIT_TEMPLATE(SUB_DOUBLE_VFP)
+JIT_TEMPLATE(MUL_DOUBLE_VFP)
+JIT_TEMPLATE(DIV_DOUBLE_VFP)
+JIT_TEMPLATE(DOUBLE_TO_FLOAT_VFP)
+JIT_TEMPLATE(DOUBLE_TO_INT_VFP)
+JIT_TEMPLATE(FLOAT_TO_DOUBLE_VFP)
+JIT_TEMPLATE(FLOAT_TO_INT_VFP)
+JIT_TEMPLATE(INT_TO_DOUBLE_VFP)
+JIT_TEMPLATE(INT_TO_FLOAT_VFP)
+JIT_TEMPLATE(CMPG_DOUBLE_VFP)
+JIT_TEMPLATE(CMPL_DOUBLE_VFP)
+JIT_TEMPLATE(CMPG_FLOAT_VFP)
+JIT_TEMPLATE(CMPL_FLOAT_VFP)
diff --git a/vm/compiler/template/armv5te/fbinop.S b/vm/compiler/template/armv5te/fbinop.S
new file mode 100644
index 0000000..3bc4b52
--- /dev/null
+++ b/vm/compiler/template/armv5te/fbinop.S
@@ -0,0 +1,14 @@
+ /*
+ * Generic 32-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ flds s0,[r1]
+ flds s1,[r2]
+ $instr
+ fsts s2,[r0]
+ bx lr
diff --git a/vm/compiler/template/armv5te/fbinopWide.S b/vm/compiler/template/armv5te/fbinopWide.S
new file mode 100644
index 0000000..3774646
--- /dev/null
+++ b/vm/compiler/template/armv5te/fbinopWide.S
@@ -0,0 +1,14 @@
+ /*
+ * Generic 64-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ fldd d0,[r1]
+ fldd d1,[r2]
+ $instr
+ fstd d2,[r0]
+ bx lr
diff --git a/vm/compiler/template/armv5te/footer.S b/vm/compiler/template/armv5te/footer.S
new file mode 100644
index 0000000..29073c3
--- /dev/null
+++ b/vm/compiler/template/armv5te/footer.S
@@ -0,0 +1,61 @@
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+ .text
+ .align 2
+.LinvokeNative:
+ @ Prep for the native call
+ @ r1 = newFP, r0 = methodToCall
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ ldr r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+ str r1, [r3, #offThread_curFrame] @ self->curFrame = newFp
+ str r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
+ @ newFp->localRefTop=refNext
+ mov r9, r3 @ r9<- glue->self (preserve)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- new stack save area
+
+ mov r2, r0 @ r2<- methodToCall
+ mov r0, r1 @ r0<- newFP
+ add r1, rGLUE, #offGlue_retval @ r1<- &retval
+
+ LDR_PC_LR "[r2, #offMethod_nativeFunc]"
+
+ @ native return; r9=self, r10=newSaveArea
+ @ equivalent to dvmPopJniLocals
+ ldr r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+ ldr r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+ ldr r1, [r9, #offThread_exception] @ check for exception
+ str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
+ cmp r1, #0 @ null?
+ str r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+ bne .LhandleException @ no, handle exception
+ bx r2
+
+/* NOTE - this path can be exercised if the JIT threshold is set to 5 */
+.LhandleException:
+ ldr r0, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+ ldr rIBASE, .LdvmAsmInstructionStart @ same as above
+ ldr rPC, [r10, #offStackSaveArea_savedPc] @ reload rPC
+ mov pc, r0 @ branch to dvmMterpCommonExceptionThrown
+
+ .align 2
+.LdvmAsmInstructionStart:
+ .word dvmAsmInstructionStart
+.LdvmJitToInterpNoChain:
+ .word dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+ .word dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+ .word dvmMterpCommonExceptionThrown
+.L__aeabi_cdcmple:
+ .word __aeabi_cdcmple
+.L__aeabi_cfcmple:
+ .word __aeabi_cfcmple
+
+ .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
diff --git a/vm/compiler/template/armv5te/funop.S b/vm/compiler/template/armv5te/funop.S
new file mode 100644
index 0000000..8409c28
--- /dev/null
+++ b/vm/compiler/template/armv5te/funop.S
@@ -0,0 +1,15 @@
+ /*
+ * Generic 32bit-to-32bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "s1 = op s0".
+ *
+ * For: float-to-int, int-to-float
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ flds s0, [r1] @ s0<- vB
+ $instr @ s1<- op s0
+ fsts s1, [r0] @ vA<- s1
+ bx lr
diff --git a/vm/compiler/template/armv5te/funopNarrower.S b/vm/compiler/template/armv5te/funopNarrower.S
new file mode 100644
index 0000000..8566fca
--- /dev/null
+++ b/vm/compiler/template/armv5te/funopNarrower.S
@@ -0,0 +1,15 @@
+ /*
+ * Generic 64bit-to-32bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ fldd d0, [r1] @ d0<- vB
+ $instr @ s0<- op d0
+ fsts s0, [r0] @ vA<- s0
+ bx lr
diff --git a/vm/compiler/template/armv5te/funopWider.S b/vm/compiler/template/armv5te/funopWider.S
new file mode 100644
index 0000000..dbe745c
--- /dev/null
+++ b/vm/compiler/template/armv5te/funopWider.S
@@ -0,0 +1,15 @@
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ flds s0, [r1] @ s0<- vB
+ $instr @ d0<- op s0
+ fstd d0, [r0] @ vA<- d0
+ bx lr
diff --git a/vm/compiler/template/armv5te/header.S b/vm/compiler/template/armv5te/header.S
new file mode 100644
index 0000000..9651032
--- /dev/null
+++ b/vm/compiler/template/armv5te/header.S
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+#if defined(WITH_JIT)
+
+/*
+ * ARMv5 definitions and declarations.
+ */
+
+/*
+ARM EABI general notes:
+
+r0-r3 hold first 4 args to a method; they are not preserved across method calls
+r4-r8 are available for general use
+r9 is given special treatment in some situations, but not for us
+r10 (sl) seems to be generally available
+r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
+r12 (ip) is scratch -- not preserved across method calls
+r13 (sp) should be managed carefully in case a signal arrives
+r14 (lr) must be preserved
+r15 (pc) can be tinkered with directly
+
+r0 holds returns of <= 4 bytes
+r0-r1 hold returns of 8 bytes, low word in r0
+
+Callee must save/restore r4+ (except r12) if it modifies them.
+
+Stack is "full descending". Only the arguments that don't fit in the first 4
+registers are placed on the stack. "sp" points at the first stacked argument
+(i.e. the 5th arg).
+
+VFP: single-precision results in s0, double-precision results in d0.
+
+In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
+64-bit quantities (long long, double) must be 64-bit aligned.
+*/
+
+/*
+JIT and ARM notes:
+
+The following registers have fixed assignments:
+
+ reg nick purpose
+ r5 rFP interpreted frame pointer, used for accessing locals and args
+ r6 rGLUE MterpGlue pointer
+
+The following registers have fixed assignments in mterp but are scratch
+registers in compiled code
+
+ reg nick purpose
+ r4 rPC interpreted program counter, used for fetching instructions
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
+
+Macros are provided for common operations. Each macro MUST emit only
+one instruction to make instruction-counting easier. They MUST NOT alter
+unspecified registers or condition codes.
+*/
+
+/* single-purpose registers, given names for clarity */
+#define rPC r4
+#define rFP r5
+#define rGLUE r6
+#define rINST r7
+#define rIBASE r8
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+#define SAVEAREA_FROM_FP(_reg, _fpreg) \
+ sub _reg, _fpreg, #sizeofStackSaveArea
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../../../mterp/common/asm-constants.h"
+
diff --git a/vm/compiler/template/armv5te/platform.S b/vm/compiler/template/armv5te/platform.S
new file mode 100644
index 0000000..b960a93
--- /dev/null
+++ b/vm/compiler/template/armv5te/platform.S
@@ -0,0 +1,16 @@
+/*
+ * ===========================================================================
+ * CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * 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
diff --git a/vm/compiler/template/config-armv5te b/vm/compiler/template/config-armv5te
new file mode 100644
index 0000000..668df1b
--- /dev/null
+++ b/vm/compiler/template/config-armv5te
@@ -0,0 +1,45 @@
+# 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.
+
+#
+# Configuration for ARMv5TE architecture targets.
+#
+
+# file header and basic definitions
+#import c/header.c
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+#import cstubs/stubdefs.c
+
+# highly-platform-specific defs
+import armv5te/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+#import c/opcommon.c
+
+# opcode list; argument to op-start is default directory
+op-start armv5te
+
+op-end
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+##import c/gotoTargets.c
+
+# end of defs; include this when cstubs/stubdefs.c is included
+#import cstubs/enddefs.c
+
+# common subroutines for asm
+import armv5te/footer.S
diff --git a/vm/compiler/template/gen-template.py b/vm/compiler/template/gen-template.py
new file mode 100755
index 0000000..8a1ba0c
--- /dev/null
+++ b/vm/compiler/template/gen-template.py
@@ -0,0 +1,422 @@
+#!/usr/bin/env python
+#
+# 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.
+
+#
+# Using instructions from an architecture-specific config file, generate C
+# and assembly source files for the Dalvik JIT.
+#
+
+import sys, string, re, time
+from string import Template
+
+interp_defs_file = "TemplateOpList.h" # need opcode list
+
+handler_size_bits = -1000
+handler_size_bytes = -1000
+in_op_start = 0 # 0=not started, 1=started, 2=ended
+default_op_dir = None
+opcode_locations = {}
+asm_stub_text = []
+label_prefix = ".L" # use ".L" to hide labels from gdb
+
+
+# Exception class.
+class DataParseError(SyntaxError):
+ "Failure when parsing data file"
+
+#
+# Set any omnipresent substitution values.
+#
+def getGlobalSubDict():
+ return { "handler_size_bits":handler_size_bits,
+ "handler_size_bytes":handler_size_bytes }
+
+#
+# Parse arch config file --
+# Set handler_size_bytes to the value of tokens[1], and handler_size_bits to
+# log2(handler_size_bytes). Throws an exception if "bytes" is not a power
+# of two.
+#
+def setHandlerSize(tokens):
+ global handler_size_bits, handler_size_bytes
+ if len(tokens) != 2:
+ raise DataParseError("handler-size requires one argument")
+ if handler_size_bits != -1000:
+ raise DataParseError("handler-size may only be set once")
+
+ # compute log2(n), and make sure n is a power of 2
+ handler_size_bytes = bytes = int(tokens[1])
+ bits = -1
+ while bytes > 0:
+ bytes //= 2 # halve with truncating division
+ bits += 1
+
+ if handler_size_bytes == 0 or handler_size_bytes != (1 << bits):
+ raise DataParseError("handler-size (%d) must be power of 2 and > 0" \
+ % orig_bytes)
+ handler_size_bits = bits
+
+#
+# Parse arch config file --
+# Copy a file in to the C or asm output file.
+#
+def importFile(tokens):
+ if len(tokens) != 2:
+ raise DataParseError("import requires one argument")
+ source = tokens[1]
+ if source.endswith(".S"):
+ appendSourceFile(tokens[1], getGlobalSubDict(), asm_fp, None)
+ else:
+ raise DataParseError("don't know how to import %s (expecting .c/.S)"
+ % source)
+
+#
+# Parse arch config file --
+# Copy a file in to the C or asm output file.
+#
+def setAsmStub(tokens):
+ global asm_stub_text
+ if len(tokens) != 2:
+ raise DataParseError("import requires one argument")
+ try:
+ stub_fp = open(tokens[1])
+ asm_stub_text = stub_fp.readlines()
+ except IOError, err:
+ stub_fp.close()
+ raise DataParseError("unable to load asm-stub: %s" % str(err))
+ stub_fp.close()
+
+#
+# Parse arch config file --
+# Start of opcode list.
+#
+def opStart(tokens):
+ global in_op_start
+ global default_op_dir
+ if len(tokens) != 2:
+ raise DataParseError("opStart takes a directory name argument")
+ if in_op_start != 0:
+ raise DataParseError("opStart can only be specified once")
+ default_op_dir = tokens[1]
+ in_op_start = 1
+
+#
+# Parse arch config file --
+# Set location of a single opcode's source file.
+#
+def opEntry(tokens):
+ #global opcode_locations
+ if len(tokens) != 3:
+ raise DataParseError("op requires exactly two arguments")
+ if in_op_start != 1:
+ raise DataParseError("op statements must be between opStart/opEnd")
+ try:
+ index = opcodes.index(tokens[1])
+ except ValueError:
+ raise DataParseError("unknown opcode %s" % tokens[1])
+ opcode_locations[tokens[1]] = tokens[2]
+
+#
+# Parse arch config file --
+# End of opcode list; emit instruction blocks.
+#
+def opEnd(tokens):
+ global in_op_start
+ if len(tokens) != 1:
+ raise DataParseError("opEnd takes no arguments")
+ if in_op_start != 1:
+ raise DataParseError("opEnd must follow opStart, and only appear once")
+ in_op_start = 2
+
+ loadAndEmitOpcodes()
+
+
+#
+# Extract an ordered list of instructions from the VM sources. We use the
+# "goto table" definition macro, which has exactly 256 entries.
+#
+def getOpcodeList():
+ opcodes = []
+ opcode_fp = open("%s/%s" % (target_arch, interp_defs_file))
+ opcode_re = re.compile(r"^JIT_TEMPLATE\((\w+)\)", re.DOTALL)
+ for line in opcode_fp:
+ match = opcode_re.match(line)
+ if not match:
+ continue
+ opcodes.append("TEMPLATE_" + match.group(1))
+ opcode_fp.close()
+
+ return opcodes
+
+
+#
+# Load and emit opcodes for all 256 instructions.
+#
+def loadAndEmitOpcodes():
+ sister_list = []
+
+ # point dvmAsmInstructionStart at the first handler or stub
+ asm_fp.write("\n .global dvmCompilerTemplateStart\n")
+ asm_fp.write(" .type dvmCompilerTemplateStart, %function\n")
+ asm_fp.write(" .text\n\n")
+ asm_fp.write("dvmCompilerTemplateStart:\n\n")
+
+ for i in xrange(len(opcodes)):
+ op = opcodes[i]
+
+ if opcode_locations.has_key(op):
+ location = opcode_locations[op]
+ else:
+ location = default_op_dir
+
+ loadAndEmitAsm(location, i, sister_list)
+
+ # Use variable sized handlers now
+ # asm_fp.write("\n .balign %d\n" % handler_size_bytes)
+ asm_fp.write(" .size dvmCompilerTemplateStart, .-dvmCompilerTemplateStart\n")
+
+#
+# Load an assembly fragment and emit it.
+#
+def loadAndEmitAsm(location, opindex, sister_list):
+ op = opcodes[opindex]
+ source = "%s/%s.S" % (location, op)
+ dict = getGlobalSubDict()
+ dict.update({ "opcode":op, "opnum":opindex })
+ print " emit %s --> asm" % source
+
+ emitAsmHeader(asm_fp, dict)
+ appendSourceFile(source, dict, asm_fp, sister_list)
+
+#
+# Output the alignment directive and label for an assembly piece.
+#
+def emitAsmHeader(outfp, dict):
+ outfp.write("/* ------------------------------ */\n")
+ # The alignment directive ensures that the handler occupies
+ # at least the correct amount of space. We don't try to deal
+ # with overflow here.
+ outfp.write(" .balign 4\n")
+ # Emit a label so that gdb will say the right thing. We prepend an
+ # underscore so the symbol name doesn't clash with the OpCode enum.
+ template_name = "dvmCompiler_%(opcode)s" % dict
+ outfp.write(" .global %s\n" % template_name);
+ outfp.write("%s:\n" % template_name);
+
+#
+# Output a generic instruction stub that updates the "glue" struct and
+# calls the C implementation.
+#
+def emitAsmStub(outfp, dict):
+ emitAsmHeader(outfp, dict)
+ for line in asm_stub_text:
+ templ = Template(line)
+ outfp.write(templ.substitute(dict))
+
+#
+# Append the file specified by "source" to the open "outfp". Each line will
+# be template-replaced using the substitution dictionary "dict".
+#
+# If the first line of the file starts with "%" it is taken as a directive.
+# A "%include" line contains a filename and, optionally, a Python-style
+# dictionary declaration with substitution strings. (This is implemented
+# with recursion.)
+#
+# If "sister_list" is provided, and we find a line that contains only "&",
+# all subsequent lines from the file will be appended to sister_list instead
+# of copied to the output.
+#
+# This may modify "dict".
+#
+def appendSourceFile(source, dict, outfp, sister_list):
+ outfp.write("/* File: %s */\n" % source)
+ infp = open(source, "r")
+ in_sister = False
+ for line in infp:
+ if line.startswith("%include"):
+ # Parse the "include" line
+ tokens = line.strip().split(' ', 2)
+ if len(tokens) < 2:
+ raise DataParseError("malformed %%include in %s" % source)
+
+ alt_source = tokens[1].strip("\"")
+ if alt_source == source:
+ raise DataParseError("self-referential %%include in %s"
+ % source)
+
+ new_dict = dict.copy()
+ if len(tokens) == 3:
+ new_dict.update(eval(tokens[2]))
+ #print " including src=%s dict=%s" % (alt_source, new_dict)
+ appendSourceFile(alt_source, new_dict, outfp, sister_list)
+ continue
+
+ elif line.startswith("%default"):
+ # copy keywords into dictionary
+ tokens = line.strip().split(' ', 1)
+ if len(tokens) < 2:
+ raise DataParseError("malformed %%default in %s" % source)
+ defaultValues = eval(tokens[1])
+ for entry in defaultValues:
+ dict.setdefault(entry, defaultValues[entry])
+ continue
+
+ elif line.startswith("%verify"):
+ # more to come, someday
+ continue
+
+ elif line.startswith("%break") and sister_list != None:
+ # allow more than one %break, ignoring all following the first
+ if not in_sister:
+ in_sister = True
+ sister_list.append("\n/* continuation for %(opcode)s */\n"%dict)
+ continue
+
+ # perform keyword substitution if a dictionary was provided
+ if dict != None:
+ templ = Template(line)
+ try:
+ subline = templ.substitute(dict)
+ except KeyError, err:
+ raise DataParseError("keyword substitution failed in %s: %s"
+ % (source, str(err)))
+ except:
+ print "ERROR: substitution failed: " + line
+ raise
+ else:
+ subline = line
+
+ # write output to appropriate file
+ if in_sister:
+ sister_list.append(subline)
+ else:
+ outfp.write(subline)
+ outfp.write("\n")
+ infp.close()
+
+#
+# Emit a C-style section header comment.
+#
+def emitSectionComment(str, fp):
+ equals = "========================================" \
+ "==================================="
+
+ fp.write("\n/*\n * %s\n * %s\n * %s\n */\n" %
+ (equals, str, equals))
+
+
+#
+# ===========================================================================
+# "main" code
+#
+
+#
+# Check args.
+#
+if len(sys.argv) != 3:
+ print "Usage: %s target-arch output-dir" % sys.argv[0]
+ sys.exit(2)
+
+target_arch = sys.argv[1]
+output_dir = sys.argv[2]
+
+#
+# Extract opcode list.
+#
+opcodes = getOpcodeList()
+#for op in opcodes:
+# print " %s" % op
+
+#
+# Open config file.
+#
+try:
+ config_fp = open("config-%s" % target_arch)
+except:
+ print "Unable to open config file 'config-%s'" % target_arch
+ sys.exit(1)
+
+#
+# Open and prepare output files.
+#
+try:
+ asm_fp = open("%s/CompilerTemplateAsm-%s.S" % (output_dir, target_arch), "w")
+except:
+ print "Unable to open output files"
+ print "Make sure directory '%s' exists and existing files are writable" \
+ % output_dir
+ # Ideally we'd remove the files to avoid confusing "make", but if they
+ # failed to open we probably won't be able to remove them either.
+ sys.exit(1)
+
+print "Generating %s" % (asm_fp.name)
+
+file_header = """/*
+ * This file was generated automatically by gen-template.py for '%s'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+""" % (target_arch)
+
+asm_fp.write(file_header)
+
+#
+# Process the config file.
+#
+failed = False
+try:
+ for line in config_fp:
+ line = line.strip() # remove CRLF, leading spaces
+ tokens = line.split(' ') # tokenize
+ #print "%d: %s" % (len(tokens), tokens)
+ if len(tokens[0]) == 0:
+ #print " blank"
+ pass
+ elif tokens[0][0] == '#':
+ #print " comment"
+ pass
+ else:
+ if tokens[0] == "handler-size":
+ setHandlerSize(tokens)
+ elif tokens[0] == "import":
+ importFile(tokens)
+ elif tokens[0] == "asm-stub":
+ setAsmStub(tokens)
+ elif tokens[0] == "op-start":
+ opStart(tokens)
+ elif tokens[0] == "op-end":
+ opEnd(tokens)
+ elif tokens[0] == "op":
+ opEntry(tokens)
+ else:
+ raise DataParseError, "unrecognized command '%s'" % tokens[0]
+except DataParseError, err:
+ print "Failed: " + str(err)
+ # TODO: remove output files so "make" doesn't get confused
+ failed = True
+ asm_fp.close()
+ c_fp = asm_fp = None
+
+config_fp.close()
+
+#
+# Done!
+#
+if asm_fp:
+ asm_fp.close()
+
+sys.exit(failed)
diff --git a/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
new file mode 100644
index 0000000..0831100
--- /dev/null
+++ b/vm/compiler/template/out/CompilerTemplateAsm-armv5te.S
@@ -0,0 +1,1158 @@
+/*
+ * This file was generated automatically by gen-template.py for 'armv5te'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: armv5te/header.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.
+ */
+
+#if defined(WITH_JIT)
+
+/*
+ * ARMv5 definitions and declarations.
+ */
+
+/*
+ARM EABI general notes:
+
+r0-r3 hold first 4 args to a method; they are not preserved across method calls
+r4-r8 are available for general use
+r9 is given special treatment in some situations, but not for us
+r10 (sl) seems to be generally available
+r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
+r12 (ip) is scratch -- not preserved across method calls
+r13 (sp) should be managed carefully in case a signal arrives
+r14 (lr) must be preserved
+r15 (pc) can be tinkered with directly
+
+r0 holds returns of <= 4 bytes
+r0-r1 hold returns of 8 bytes, low word in r0
+
+Callee must save/restore r4+ (except r12) if it modifies them.
+
+Stack is "full descending". Only the arguments that don't fit in the first 4
+registers are placed on the stack. "sp" points at the first stacked argument
+(i.e. the 5th arg).
+
+VFP: single-precision results in s0, double-precision results in d0.
+
+In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
+64-bit quantities (long long, double) must be 64-bit aligned.
+*/
+
+/*
+JIT and ARM notes:
+
+The following registers have fixed assignments:
+
+ reg nick purpose
+ r5 rFP interpreted frame pointer, used for accessing locals and args
+ r6 rGLUE MterpGlue pointer
+
+The following registers have fixed assignments in mterp but are scratch
+registers in compiled code
+
+ reg nick purpose
+ r4 rPC interpreted program counter, used for fetching instructions
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
+
+Macros are provided for common operations. Each macro MUST emit only
+one instruction to make instruction-counting easier. They MUST NOT alter
+unspecified registers or condition codes.
+*/
+
+/* single-purpose registers, given names for clarity */
+#define rPC r4
+#define rFP r5
+#define rGLUE r6
+#define rINST r7
+#define rIBASE r8
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+#define SAVEAREA_FROM_FP(_reg, _fpreg) \
+ sub _reg, _fpreg, #sizeofStackSaveArea
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../../../mterp/common/asm-constants.h"
+
+
+/* File: armv5te/platform.S */
+/*
+ * ===========================================================================
+ * CPU-version-specific defines
+ * ===========================================================================
+ */
+
+/*
+ * 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
+
+
+ .global dvmCompilerTemplateStart
+ .type dvmCompilerTemplateStart, %function
+ .text
+
+dvmCompilerTemplateStart:
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMP_LONG
+dvmCompiler_TEMPLATE_CMP_LONG:
+/* File: armv5te/TEMPLATE_CMP_LONG.S */
+ /*
+ * Compare two 64-bit values. Puts 0, 1, or -1 into the destination
+ * register based on the results of the comparison.
+ *
+ * We load the full values with LDM, but in practice many values could
+ * be resolved by only looking at the high word. This could be made
+ * faster or slower by splitting the LDM into a pair of LDRs.
+ *
+ * If we just wanted to set condition flags, we could do this:
+ * subs ip, r0, r2
+ * sbcs ip, r1, r3
+ * subeqs ip, r0, r2
+ * Leaving { <0, 0, >0 } in ip. However, we have to set it to a specific
+ * integer value, which we can do with 2 conditional mov/mvn instructions
+ * (set 1, set -1; if they're equal we already have 0 in ip), giving
+ * us a constant 5-cycle path plus a branch at the end to the
+ * instruction epilogue code. The multi-compare approach below needs
+ * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
+ * in the worst case (the 64-bit values are equal).
+ */
+ /* cmp-long vAA, vBB, vCC */
+ cmp r1, r3 @ compare (vBB+1, vCC+1)
+ blt .LTEMPLATE_CMP_LONG_less @ signed compare on high part
+ bgt .LTEMPLATE_CMP_LONG_greater
+ subs r0, r0, r2 @ r0<- r0 - r2
+ bxeq lr
+ bhi .LTEMPLATE_CMP_LONG_greater @ unsigned compare on low part
+.LTEMPLATE_CMP_LONG_less:
+ mvn r0, #0 @ r0<- -1
+ bx lr
+.LTEMPLATE_CMP_LONG_greater:
+ mov r0, #1 @ r0<- 1
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_RETURN
+dvmCompiler_TEMPLATE_RETURN:
+/* File: armv5te/TEMPLATE_RETURN.S */
+ /*
+ * Unwind a frame from the Dalvik stack for compiled OP_RETURN_XXX.
+ * If the stored value in returnAddr
+ * is non-zero, the caller is compiled by the JIT thus return to the
+ * address in the code cache following the invoke instruction. Otherwise
+ * return to the special dvmJitToInterpNoChain entry point.
+ */
+ SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
+ ldr r10, [r0, #offStackSaveArea_prevFrame] @ r10<- saveArea->prevFrame
+ ldr r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+ ldr rPC, [r0, #offStackSaveArea_savedPc] @ rPC<- saveArea->savedPc
+ ldr r9, [r0, #offStackSaveArea_returnAddr] @ r9<- chaining cell ret
+ ldr r2, [r10, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ @ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ cmp r2, #0 @ break frame?
+ beq 1f @ bail to interpreter
+ ldr r0, .LdvmJitToInterpNoChain @ defined in footer.S
+ mov rFP, r10 @ publish new FP
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+ ldr r8, [r8] @ r8<- suspendCount
+
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+ str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
+ add rPC, rPC, #6 @ publish new rPC (advance 6 bytes)
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r8, #0 @ check the suspendCount
+ movne r9, #0 @ clear the chaining cell address
+ cmp r9, #0 @ chaining cell exists?
+ blxne r9 @ jump to the chaining cell
+ mov pc, r0 @ callsite is interpreted
+1:
+ stmia rGLUE, {rPC, rFP} @ SAVE_PC_FP_TO_GLUE()
+ ldr r2, .LdvmMterpStdBail @ defined in footer.S
+ mov r1, #0 @ changeInterp = false
+ mov r0, rGLUE @ Expecting rGLUE in r0
+ blx r2 @ exit the interpreter
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT
+dvmCompiler_TEMPLATE_INVOKE_METHOD_NO_OPT:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_NO_OPT.S */
+ /*
+ * For polymorphic callsites - setup the Dalvik frame and load Dalvik PC
+ * into rPC then jump to dvmJitToInterpNoChain to dispatch the
+ * runtime-resolved callee.
+ */
+ @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+ ldrh r7, [r0, #offMethod_registersSize] @ r7<- methodToCall->regsSize
+ ldrh r2, [r0, #offMethod_outsSize] @ r2<- methodToCall->outsSize
+ ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
+ ldr r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+ add r3, r1, #1 @ Thumb addr is odd
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
+ sub r1, r1, r7, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
+ sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
+ ldr r8, [r8] @ r3<- suspendCount (int)
+ cmp r10, r9 @ bottom < interpStackEnd?
+ bxlt 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
+ str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+ str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+ ldr rPC, [r0, #offMethod_insns] @ rPC<- methodToCall->insns
+
+
+ @ set up newSaveArea
+ str rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+ str r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+ str r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ cmp r8, #0 @ suspendCount != 0
+ bxne lr @ bail to the interpreter
+ tst r10, #ACC_NATIVE
+ bne .LinvokeNative
+ /*
+ * If we want to punt to the interpreter for native call, swap the bne with
+ * the following
+ * bxne lr
+ */
+
+
+ ldr r10, .LdvmJitToInterpNoChain
+ ldr r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
+
+ @ Update "glue" values for the new method
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ mov rFP, r1 @ fp = newFp
+ str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
+
+ @ Start executing the callee
+ mov pc, r10 @ dvmJitToInterpNoChain
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN
+dvmCompiler_TEMPLATE_INVOKE_METHOD_CHAIN:
+/* File: armv5te/TEMPLATE_INVOKE_METHOD_CHAIN.S */
+ /*
+ * For monomorphic callsite, setup the Dalvik frame and return to the
+ * Thumb code through the link register to transfer control to the callee
+ * method through a dedicated chaining cell.
+ */
+ @ r0 = methodToCall, r1 = returnCell, rPC = dalvikCallsite
+ ldrh r7, [r0, #offMethod_registersSize] @ r7<- methodToCall->regsSize
+ ldrh r2, [r0, #offMethod_outsSize] @ r2<- methodToCall->outsSize
+ ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
+ ldr r8, [rGLUE, #offGlue_pSelfSuspendCount] @ r8<- &suspendCount
+ add r3, r1, #1 @ Thumb addr is odd
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
+ sub r1, r1, r7, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- stack save area
+ add r12, lr, #2 @ setup the punt-to-interp address
+ sub r10, r10, r2, lsl #2 @ r10<- bottom (newsave - outsSize)
+ ldr r8, [r8] @ r3<- suspendCount (int)
+ cmp r10, r9 @ bottom < interpStackEnd?
+ bxlt r12 @ 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
+ str rPC, [rFP, #(offStackSaveArea_currentPc - sizeofStackSaveArea)]
+ str rPC, [r1, #(offStackSaveArea_savedPc - sizeofStackSaveArea)]
+ ldr rPC, [r0, #offMethod_insns] @ rPC<- methodToCall->insns
+
+
+ @ set up newSaveArea
+ str rFP, [r1, #(offStackSaveArea_prevFrame - sizeofStackSaveArea)]
+ str r3, [r1, #(offStackSaveArea_returnAddr - sizeofStackSaveArea)]
+ str r0, [r1, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ cmp r8, #0 @ suspendCount != 0
+ bxne r12 @ bail to the interpreter
+ tst r10, #ACC_NATIVE
+ bne .LinvokeNative
+ /*
+ * If we want to punt to the interpreter for native call, swap the bne with
+ * the following
+ * bxne r12
+ */
+
+
+ ldr r3, [r9, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
+
+ @ Update "glue" values for the new method
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ mov rFP, r1 @ fp = newFp
+ str rFP, [r2, #offThread_curFrame] @ self->curFrame = newFp
+
+ bx lr @ return to the callee-chaining cell
+
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPG_DOUBLE
+dvmCompiler_TEMPLATE_CMPG_DOUBLE:
+/* File: armv5te/TEMPLATE_CMPG_DOUBLE.S */
+/* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
+ /*
+ * For the JIT: incoming arguments are pointers to the arguments in r0/r1
+ * result in r0
+ *
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * See OP_CMPL_FLOAT for an explanation.
+ *
+ * For: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+ mov r4, lr @ save return address
+ mov r9, r0 @ save copy of &arg1
+ mov r10, r1 @ save copy of &arg2
+ ldmia r9, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r10, {r2-r3} @ r2/r3<- vCC/vCC+1
+ LDR_PC_LR ".L__aeabi_cdcmple" @ PIC way of "bl __aeabi_cdcmple"
+ bhi .LTEMPLATE_CMPG_DOUBLE_gt_or_nan @ C set and Z clear, disambiguate
+ mvncc r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0, trumps less than
+ bx r4
+
+ @ Test for NaN with a second comparison. EABI forbids testing bit
+ @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+ @ make the library call.
+.LTEMPLATE_CMPG_DOUBLE_gt_or_nan:
+ ldmia r10, {r0-r1} @ reverse order
+ ldmia r9, {r2-r3}
+ LDR_PC_LR ".L__aeabi_cdcmple" @ r0<- Z set if eq, C clear if <
+ movcc r0, #1 @ (greater than) r1<- 1
+ bxcc r4
+ mov r0, #1 @ r1<- 1 or -1 for NaN
+ bx r4
+
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPL_DOUBLE
+dvmCompiler_TEMPLATE_CMPL_DOUBLE:
+/* File: armv5te/TEMPLATE_CMPL_DOUBLE.S */
+ /*
+ * For the JIT: incoming arguments are pointers to the arguments in r0/r1
+ * result in r0
+ *
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * See OP_CMPL_FLOAT for an explanation.
+ *
+ * For: cmpl-double, cmpg-double
+ */
+ /* op vAA, vBB, vCC */
+ mov r4, lr @ save return address
+ mov r9, r0 @ save copy of &arg1
+ mov r10, r1 @ save copy of &arg2
+ ldmia r9, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r10, {r2-r3} @ r2/r3<- vCC/vCC+1
+ LDR_PC_LR ".L__aeabi_cdcmple" @ PIC way of "bl __aeabi_cdcmple"
+ bhi .LTEMPLATE_CMPL_DOUBLE_gt_or_nan @ C set and Z clear, disambiguate
+ mvncc r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0, trumps less than
+ bx r4
+
+ @ Test for NaN with a second comparison. EABI forbids testing bit
+ @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+ @ make the library call.
+.LTEMPLATE_CMPL_DOUBLE_gt_or_nan:
+ ldmia r10, {r0-r1} @ reverse order
+ ldmia r9, {r2-r3}
+ LDR_PC_LR ".L__aeabi_cdcmple" @ r0<- Z set if eq, C clear if <
+ movcc r0, #1 @ (greater than) r1<- 1
+ bxcc r4
+ mvn r0, #0 @ r1<- 1 or -1 for NaN
+ bx r4
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPG_FLOAT
+dvmCompiler_TEMPLATE_CMPG_FLOAT:
+/* File: armv5te/TEMPLATE_CMPG_FLOAT.S */
+/* File: armv5te/TEMPLATE_CMPL_FLOAT.S */
+ /*
+ * For the JIT: incoming arguments in r0, r1
+ * result in r0
+ *
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * The straightforward implementation requires 3 calls to functions
+ * that return a result in r0. We can do it with two calls if our
+ * EABI library supports __aeabi_cfcmple (only one if we want to check
+ * for NaN directly):
+ * check x <= y
+ * if <, return -1
+ * if ==, return 0
+ * check y <= x
+ * if <, return 1
+ * return {-1,1}
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+ mov r4, lr @ save return address
+ mov r9, r0 @ Save copies - we may need to redo
+ mov r10, r1
+ LDR_PC_LR ".L__aeabi_cfcmple" @ cmp <=: C clear if <, Z set if eq
+ bhi .LTEMPLATE_CMPG_FLOAT_gt_or_nan @ C set and Z clear, disambiguate
+ mvncc r0, #0 @ (less than) r0<- -1
+ moveq r0, #0 @ (equal) r0<- 0, trumps less than
+ bx r4
+ @ Test for NaN with a second comparison. EABI forbids testing bit
+ @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+ @ make the library call.
+.LTEMPLATE_CMPG_FLOAT_gt_or_nan:
+ mov r1, r9 @ reverse order
+ mov r0, r10
+ LDR_PC_LR ".L__aeabi_cfcmple" @ r0<- Z set if eq, C clear if <
+ movcc r0, #1 @ (greater than) r1<- 1
+ bxcc r4
+ mov r0, #1 @ r1<- 1 or -1 for NaN
+ bx r4
+
+
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPL_FLOAT
+dvmCompiler_TEMPLATE_CMPL_FLOAT:
+/* File: armv5te/TEMPLATE_CMPL_FLOAT.S */
+ /*
+ * For the JIT: incoming arguments in r0, r1
+ * result in r0
+ *
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * Provide a "naninst" instruction that puts 1 or -1 into r1 depending
+ * on what value we'd like to return when one of the operands is NaN.
+ *
+ * The operation we're implementing is:
+ * if (x == y)
+ * return 0;
+ * else if (x < y)
+ * return -1;
+ * else if (x > y)
+ * return 1;
+ * else
+ * return {-1,1}; // one or both operands was NaN
+ *
+ * The straightforward implementation requires 3 calls to functions
+ * that return a result in r0. We can do it with two calls if our
+ * EABI library supports __aeabi_cfcmple (only one if we want to check
+ * for NaN directly):
+ * check x <= y
+ * if <, return -1
+ * if ==, return 0
+ * check y <= x
+ * if <, return 1
+ * return {-1,1}
+ *
+ * for: cmpl-float, cmpg-float
+ */
+ /* op vAA, vBB, vCC */
+ mov r4, lr @ save return address
+ mov r9, r0 @ Save copies - we may need to redo
+ mov r10, r1
+ LDR_PC_LR ".L__aeabi_cfcmple" @ cmp <=: C clear if <, Z set if eq
+ bhi .LTEMPLATE_CMPL_FLOAT_gt_or_nan @ C set and Z clear, disambiguate
+ mvncc r0, #0 @ (less than) r0<- -1
+ moveq r0, #0 @ (equal) r0<- 0, trumps less than
+ bx r4
+ @ Test for NaN with a second comparison. EABI forbids testing bit
+ @ patterns, and we can't represent 0x7fc00000 in immediate form, so
+ @ make the library call.
+.LTEMPLATE_CMPL_FLOAT_gt_or_nan:
+ mov r1, r9 @ reverse order
+ mov r0, r10
+ LDR_PC_LR ".L__aeabi_cfcmple" @ r0<- Z set if eq, C clear if <
+ movcc r0, #1 @ (greater than) r1<- 1
+ bxcc r4
+ mvn r0, #0 @ r1<- 1 or -1 for NaN
+ bx r4
+
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MUL_LONG
+dvmCompiler_TEMPLATE_MUL_LONG:
+/* File: armv5te/TEMPLATE_MUL_LONG.S */
+ /*
+ * Signed 64-bit integer multiply.
+ *
+ * For JIT: op1 in r0/r1, op2 in r2/r3, return in r0/r1
+ *
+ * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
+ * WX
+ * x YZ
+ * --------
+ * ZW ZX
+ * YW YX
+ *
+ * The low word of the result holds ZX, the high word holds
+ * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
+ * it doesn't fit in the low 64 bits.
+ *
+ * Unlike most ARM math operations, multiply instructions have
+ * restrictions on using the same register more than once (Rd and Rm
+ * cannot be the same).
+ */
+ /* mul-long vAA, vBB, vCC */
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ mov r0,r9
+ mov r1,r10
+ bx lr
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SHL_LONG
+dvmCompiler_TEMPLATE_SHL_LONG:
+/* File: armv5te/TEMPLATE_SHL_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shl-long vAA, vBB, vCC */
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ bx lr
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SHR_LONG
+dvmCompiler_TEMPLATE_SHR_LONG:
+/* File: armv5te/TEMPLATE_SHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* shr-long vAA, vBB, vCC */
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
+ mov r1, r1, asr r2 @ r1<- r1 >> r2
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_USHR_LONG
+dvmCompiler_TEMPLATE_USHR_LONG:
+/* File: armv5te/TEMPLATE_USHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to ignore all but the low
+ * 6 bits.
+ */
+ /* ushr-long vAA, vBB, vCC */
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
+ mov r1, r1, lsr r2 @ r1<- r1 >>> r2
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_ADD_FLOAT_VFP
+dvmCompiler_TEMPLATE_ADD_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_ADD_FLOAT_VFP.S */
+/* File: armv5te/fbinop.S */
+ /*
+ * Generic 32-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ flds s0,[r1]
+ flds s1,[r2]
+ fadds s2, s0, s1
+ fsts s2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SUB_FLOAT_VFP
+dvmCompiler_TEMPLATE_SUB_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_SUB_FLOAT_VFP.S */
+/* File: armv5te/fbinop.S */
+ /*
+ * Generic 32-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ flds s0,[r1]
+ flds s1,[r2]
+ fsubs s2, s0, s1
+ fsts s2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MUL_FLOAT_VFP
+dvmCompiler_TEMPLATE_MUL_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_MUL_FLOAT_VFP.S */
+/* File: armv5te/fbinop.S */
+ /*
+ * Generic 32-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ flds s0,[r1]
+ flds s1,[r2]
+ fmuls s2, s0, s1
+ fsts s2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DIV_FLOAT_VFP
+dvmCompiler_TEMPLATE_DIV_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_DIV_FLOAT_VFP.S */
+/* File: armv5te/fbinop.S */
+ /*
+ * Generic 32-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ flds s0,[r1]
+ flds s1,[r2]
+ fdivs s2, s0, s1
+ fsts s2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_ADD_DOUBLE_VFP
+dvmCompiler_TEMPLATE_ADD_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_ADD_DOUBLE_VFP.S */
+/* File: armv5te/fbinopWide.S */
+ /*
+ * Generic 64-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ fldd d0,[r1]
+ fldd d1,[r2]
+ faddd d2, d0, d1
+ fstd d2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_SUB_DOUBLE_VFP
+dvmCompiler_TEMPLATE_SUB_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_SUB_DOUBLE_VFP.S */
+/* File: armv5te/fbinopWide.S */
+ /*
+ * Generic 64-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ fldd d0,[r1]
+ fldd d1,[r2]
+ fsubd d2, d0, d1
+ fstd d2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_MUL_DOUBLE_VFP
+dvmCompiler_TEMPLATE_MUL_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_MUL_DOUBLE_VFP.S */
+/* File: armv5te/fbinopWide.S */
+ /*
+ * Generic 64-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ fldd d0,[r1]
+ fldd d1,[r2]
+ fmuld d2, d0, d1
+ fstd d2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DIV_DOUBLE_VFP
+dvmCompiler_TEMPLATE_DIV_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_DIV_DOUBLE_VFP.S */
+/* File: armv5te/fbinopWide.S */
+ /*
+ * Generic 64-bit floating point operation. Provide an "instr" line that
+ * specifies an instruction that performs s2 = s0 op s1.
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = op1 address
+ * r2 = op2 address
+ */
+ fldd d0,[r1]
+ fldd d1,[r2]
+ fdivd d2, d0, d1
+ fstd d2,[r0]
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DOUBLE_TO_FLOAT_VFP
+dvmCompiler_TEMPLATE_DOUBLE_TO_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_DOUBLE_TO_FLOAT_VFP.S */
+/* File: armv5te/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ fldd d0, [r1] @ d0<- vB
+ fcvtsd s0, d0 @ s0<- op d0
+ fsts s0, [r0] @ vA<- s0
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_DOUBLE_TO_INT_VFP
+dvmCompiler_TEMPLATE_DOUBLE_TO_INT_VFP:
+/* File: armv5te/TEMPLATE_DOUBLE_TO_INT_VFP.S */
+/* File: armv5te/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ fldd d0, [r1] @ d0<- vB
+ ftosizd s0, d0 @ s0<- op d0
+ fsts s0, [r0] @ vA<- s0
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_FLOAT_TO_DOUBLE_VFP
+dvmCompiler_TEMPLATE_FLOAT_TO_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_FLOAT_TO_DOUBLE_VFP.S */
+/* File: armv5te/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ flds s0, [r1] @ s0<- vB
+ fcvtds d0, s0 @ d0<- op s0
+ fstd d0, [r0] @ vA<- d0
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_FLOAT_TO_INT_VFP
+dvmCompiler_TEMPLATE_FLOAT_TO_INT_VFP:
+/* File: armv5te/TEMPLATE_FLOAT_TO_INT_VFP.S */
+/* File: armv5te/funop.S */
+ /*
+ * Generic 32bit-to-32bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "s1 = op s0".
+ *
+ * For: float-to-int, int-to-float
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ flds s0, [r1] @ s0<- vB
+ ftosizs s1, s0 @ s1<- op s0
+ fsts s1, [r0] @ vA<- s1
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INT_TO_DOUBLE_VFP
+dvmCompiler_TEMPLATE_INT_TO_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_INT_TO_DOUBLE_VFP.S */
+/* File: armv5te/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ flds s0, [r1] @ s0<- vB
+ fsitod d0, s0 @ d0<- op s0
+ fstd d0, [r0] @ vA<- d0
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_INT_TO_FLOAT_VFP
+dvmCompiler_TEMPLATE_INT_TO_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_INT_TO_FLOAT_VFP.S */
+/* File: armv5te/funop.S */
+ /*
+ * Generic 32bit-to-32bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "s1 = op s0".
+ *
+ * For: float-to-int, int-to-float
+ *
+ * On entry:
+ * r0 = target dalvik register address
+ * r1 = src dalvik register address
+ */
+ /* unop vA, vB */
+ flds s0, [r1] @ s0<- vB
+ fsitos s1, s0 @ s1<- op s0
+ fsts s1, [r0] @ vA<- s1
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP
+dvmCompiler_TEMPLATE_CMPG_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_CMPG_DOUBLE_VFP.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ *
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ fldd d0, [r0] @ d0<- vBB
+ fldd d1, [r1] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ mov r0, #1 @ r0<- 1 (default)
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r0<- -1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
+
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP
+dvmCompiler_TEMPLATE_CMPL_DOUBLE_VFP:
+/* File: armv5te/TEMPLATE_CMPL_DOUBLE_VFP.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ fldd d0, [r0] @ d0<- vBB
+ fldd d1, [r1] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ mvn r0, #0 @ r0<- -1 (default)
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r0<- 1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPG_FLOAT_VFP
+dvmCompiler_TEMPLATE_CMPG_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_CMPG_FLOAT_VFP.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ flds s0, [r0] @ d0<- vBB
+ flds s1, [r1] @ d1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ mov r0, #1 @ r0<- 1 (default)
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r0<- -1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
+
+/* ------------------------------ */
+ .balign 4
+ .global dvmCompiler_TEMPLATE_CMPL_FLOAT_VFP
+dvmCompiler_TEMPLATE_CMPL_FLOAT_VFP:
+/* File: armv5te/TEMPLATE_CMPL_FLOAT_VFP.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ * On entry:
+ * r0 = &op1 [vBB]
+ * r1 = &op2 [vCC]
+ */
+ /* op vAA, vBB, vCC */
+ flds s0, [r0] @ d0<- vBB
+ flds s1, [r1] @ d1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ mvn r0, #0 @ r0<- -1 (default)
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r0<- 1
+ moveq r0, #0 @ (equal) r0<- 0
+ bx lr
+
+ .size dvmCompilerTemplateStart, .-dvmCompilerTemplateStart
+/* File: armv5te/footer.S */
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+ .text
+ .align 2
+.LinvokeNative:
+ @ Prep for the native call
+ @ r1 = newFP, r0 = methodToCall
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ ldr r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+ str r1, [r3, #offThread_curFrame] @ self->curFrame = newFp
+ str r9, [r1, #(offStackSaveArea_localRefTop - sizeofStackSaveArea)]
+ @ newFp->localRefTop=refNext
+ mov r9, r3 @ r9<- glue->self (preserve)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- new stack save area
+
+ mov r2, r0 @ r2<- methodToCall
+ mov r0, r1 @ r0<- newFP
+ add r1, rGLUE, #offGlue_retval @ r1<- &retval
+
+ LDR_PC_LR "[r2, #offMethod_nativeFunc]"
+
+ @ native return; r9=self, r10=newSaveArea
+ @ equivalent to dvmPopJniLocals
+ ldr r2, [r10, #offStackSaveArea_returnAddr] @ r2 = chaining cell ret
+ ldr r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+ ldr r1, [r9, #offThread_exception] @ check for exception
+ str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
+ cmp r1, #0 @ null?
+ str r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+ bne .LhandleException @ no, handle exception
+ bx r2
+
+/* FIXME - untested */
+.LhandleException:
+ ldr r0, .LdvmMterpCommonExceptionThrown @ PIC way of getting &func
+ ldr rIBASE, .LdvmAsmInstructionStart @ same as above
+ ldr rPC, [r10, #offStackSaveArea_savedPc] @ reload rPC
+ mov pc, r0 @ branch to dvmMterpCommonExceptionThrown
+
+ .align 2
+.LdvmAsmInstructionStart:
+ .word dvmAsmInstructionStart
+.LdvmJitToInterpNoChain:
+ .word dvmJitToInterpNoChain
+.LdvmMterpStdBail:
+ .word dvmMterpStdBail
+.LdvmMterpCommonExceptionThrown:
+ .word dvmMterpCommonExceptionThrown
+.L__aeabi_cdcmple:
+ .word __aeabi_cdcmple
+.L__aeabi_cfcmple:
+ .word __aeabi_cfcmple
+
+ .global dmvCompilerTemplateEnd
+dmvCompilerTemplateEnd:
+
+#endif /* WITH_JIT */
+
diff --git a/vm/compiler/template/rebuild.sh b/vm/compiler/template/rebuild.sh
new file mode 100755
index 0000000..07d9516
--- /dev/null
+++ b/vm/compiler/template/rebuild.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+#
+# 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.
+
+#
+# Rebuild for all known targets. Necessary until the stuff in "out" gets
+# generated as part of the build.
+#
+set -e
+for arch in armv5te; do TARGET_ARCH_EXT=$arch make -f Makefile-template; done
+
diff --git a/vm/interp/Interp.c b/vm/interp/Interp.c
index 27b9582..20395cc 100644
--- a/vm/interp/Interp.c
+++ b/vm/interp/Interp.c
@@ -389,6 +389,7 @@
static inline s4 s4FromSwitchData(const void* switchData) {
u2* data = switchData;
return data[0] | (((s4) data[1]) << 16);
+}
#endif
/*
@@ -514,6 +515,62 @@
}
/*
+ * Copy data for a fill-array-data instruction. On a little-endian machine
+ * we can just do a memcpy(), on a big-endian system we have work to do.
+ *
+ * The trick here is that dexopt has byte-swapped each code unit, which is
+ * exactly what we want for short/char data. For byte data we need to undo
+ * the swap, and for 4- or 8-byte values we need to swap pieces within
+ * each word.
+ */
+static void copySwappedArrayData(void* dest, const u2* src, u4 size, u2 width)
+{
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ memcpy(dest, src, size*width);
+#else
+ int i;
+
+ switch (width) {
+ case 1:
+ /* un-swap pairs of bytes as we go */
+ for (i = (size-1) & ~1; i >= 0; i -= 2) {
+ ((u1*)dest)[i] = ((u1*)src)[i+1];
+ ((u1*)dest)[i+1] = ((u1*)src)[i];
+ }
+ /*
+ * "src" is padded to end on a two-byte boundary, but we don't want to
+ * assume "dest" is, so we handle odd length specially.
+ */
+ if ((size & 1) != 0) {
+ ((u1*)dest)[size-1] = ((u1*)src)[size];
+ }
+ break;
+ case 2:
+ /* already swapped correctly */
+ memcpy(dest, src, size*width);
+ break;
+ case 4:
+ /* swap word halves */
+ for (i = 0; i < (int) size; i++) {
+ ((u4*)dest)[i] = (src[(i << 1) + 1] << 16) | src[i << 1];
+ }
+ break;
+ case 8:
+ /* swap word halves and words */
+ for (i = 0; i < (int) (size << 1); i += 2) {
+ ((int*)dest)[i] = (src[(i << 1) + 3] << 16) | src[(i << 1) + 2];
+ ((int*)dest)[i+1] = (src[(i << 1) + 1] << 16) | src[i << 1];
+ }
+ break;
+ default:
+ LOGE("Unexpected width %d in copySwappedArrayData\n", width);
+ dvmAbort();
+ break;
+ }
+#endif
+}
+
+/*
* Fill the array with predefined constant values.
*
* Returns true if job is completed, otherwise false to indicate that
@@ -551,7 +608,7 @@
dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", NULL);
return false;
}
- memcpy(arrayObj->contents, &arrayData[4], size*width);
+ copySwappedArrayData(arrayObj->contents, &arrayData[4], size, width);
return true;
}
@@ -634,6 +691,160 @@
}
+
+/*
+ * Helpers for dvmThrowVerificationError().
+ *
+ * Each returns a newly-allocated string.
+ */
+#define kThrowShow_accessFromClass 1
+static char* classNameFromIndex(const Method* method, int ref, int flags)
+{
+ static const int kBufLen = 256;
+ const DvmDex* pDvmDex = method->clazz->pDvmDex;
+ const char* className = dexStringByTypeIdx(pDvmDex->pDexFile, ref);
+ char* dotClassName = dvmDescriptorToDot(className);
+ if (flags == 0)
+ return dotClassName;
+
+ char* result = (char*) malloc(kBufLen);
+
+ if ((flags & kThrowShow_accessFromClass) != 0) {
+ char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
+ snprintf(result, kBufLen, "tried to access class %s from class %s",
+ dotClassName, dotFromName);
+ free(dotFromName);
+ } else {
+ assert(false); // should've been caught above
+ result[0] = '\0';
+ }
+
+ free(dotClassName);
+ return result;
+}
+static char* fieldNameFromIndex(const Method* method, int ref, int flags)
+{
+ static const int kBufLen = 256;
+ const DvmDex* pDvmDex = method->clazz->pDvmDex;
+ const DexFieldId* pFieldId;
+ const char* className;
+ const char* fieldName;
+
+ pFieldId = dexGetFieldId(pDvmDex->pDexFile, ref);
+ className = dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->classIdx);
+ fieldName = dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);
+
+ char* dotName = dvmDescriptorToDot(className);
+ char* result = (char*) malloc(kBufLen);
+
+ if ((flags & kThrowShow_accessFromClass) != 0) {
+ char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
+ snprintf(result, kBufLen, "tried to access field %s.%s from class %s",
+ dotName, fieldName, dotFromName);
+ free(dotFromName);
+ } else {
+ snprintf(result, kBufLen, "%s.%s", dotName, fieldName);
+ }
+
+ free(dotName);
+ return result;
+}
+static char* methodNameFromIndex(const Method* method, int ref, int flags)
+{
+ static const int kBufLen = 384;
+ const DvmDex* pDvmDex = method->clazz->pDvmDex;
+ const DexMethodId* pMethodId;
+ const char* className;
+ const char* methodName;
+
+ pMethodId = dexGetMethodId(pDvmDex->pDexFile, ref);
+ className = dexStringByTypeIdx(pDvmDex->pDexFile, pMethodId->classIdx);
+ methodName = dexStringById(pDvmDex->pDexFile, pMethodId->nameIdx);
+
+ char* dotName = dvmDescriptorToDot(className);
+ char* result = (char*) malloc(kBufLen);
+
+ if ((flags & kThrowShow_accessFromClass) != 0) {
+ char* dotFromName = dvmDescriptorToDot(method->clazz->descriptor);
+ char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+ snprintf(result, kBufLen,
+ "tried to access method %s.%s:%s from class %s",
+ dotName, methodName, desc, dotFromName);
+ free(dotFromName);
+ free(desc);
+ } else {
+ snprintf(result, kBufLen, "%s.%s", dotName, methodName);
+ }
+
+ free(dotName);
+ return result;
+}
+
+/*
+ * Throw an exception for a problem identified by the verifier.
+ *
+ * This is used by the invoke-verification-error instruction. It always
+ * throws an exception.
+ *
+ * "kind" indicates the kind of failure encountered by the verifier. The
+ * meaning of "ref" is kind-specific; it's usually an index to a
+ * class, field, or method reference.
+ */
+void dvmThrowVerificationError(const Method* method, int kind, int ref)
+{
+ const char* exceptionName = "Ljava/lang/VerifyError;";
+ char* msg = NULL;
+
+ switch ((VerifyError) kind) {
+ case VERIFY_ERROR_NO_CLASS:
+ exceptionName = "Ljava/lang/NoClassDefFoundError;";
+ msg = classNameFromIndex(method, ref, 0);
+ break;
+ case VERIFY_ERROR_NO_FIELD:
+ exceptionName = "Ljava/lang/NoSuchFieldError;";
+ msg = fieldNameFromIndex(method, ref, 0);
+ break;
+ case VERIFY_ERROR_NO_METHOD:
+ exceptionName = "Ljava/lang/NoSuchMethodError;";
+ msg = methodNameFromIndex(method, ref, 0);
+ break;
+ case VERIFY_ERROR_ACCESS_CLASS:
+ exceptionName = "Ljava/lang/IllegalAccessError;";
+ msg = classNameFromIndex(method, ref, kThrowShow_accessFromClass);
+ break;
+ case VERIFY_ERROR_ACCESS_FIELD:
+ exceptionName = "Ljava/lang/IllegalAccessError;";
+ msg = fieldNameFromIndex(method, ref, kThrowShow_accessFromClass);
+ break;
+ case VERIFY_ERROR_ACCESS_METHOD:
+ exceptionName = "Ljava/lang/IllegalAccessError;";
+ msg = methodNameFromIndex(method, ref, kThrowShow_accessFromClass);
+ break;
+ case VERIFY_ERROR_CLASS_CHANGE:
+ exceptionName = "Ljava/lang/IncompatibleClassChangeError;";
+ msg = classNameFromIndex(method, ref, 0);
+ break;
+ case VERIFY_ERROR_INSTANTIATION:
+ exceptionName = "Ljava/lang/InstantiationError;";
+ msg = classNameFromIndex(method, ref, 0);
+ break;
+
+ case VERIFY_ERROR_GENERIC:
+ /* generic VerifyError; use default exception, no message */
+ break;
+ case VERIFY_ERROR_NONE:
+ /* should never happen; use default exception */
+ assert(false);
+ msg = strdup("weird - no error specified");
+ break;
+
+ /* no default clause -- want warning if enum updated */
+ }
+
+ dvmThrowException(exceptionName, msg);
+ free(msg);
+}
+
/*
* Main interpreter loop entry point. Select "standard" or "debug"
* interpreter and switch between them as required.
@@ -649,6 +860,27 @@
{
InterpState interpState;
bool change;
+#if defined(WITH_JIT)
+ /* Interpreter entry points from compiled code */
+ extern void dvmJitToInterpNormal();
+ extern void dvmJitToInterpNoChain();
+ extern void dvmJitToInterpPunt();
+ extern void dvmJitToInterpSingleStep();
+ extern void dvmJitToTraceSelect();
+
+ /*
+ * Reserve a static entity here to quickly setup runtime contents as
+ * gcc will issue block copy instructions.
+ */
+ static struct JitToInterpEntries jitToInterpEntries = {
+ dvmJitToInterpNormal,
+ dvmJitToInterpNoChain,
+ dvmJitToInterpPunt,
+ dvmJitToInterpSingleStep,
+ dvmJitToTraceSelect,
+ };
+#endif
+
#if defined(WITH_TRACKREF_CHECKS)
interpState.debugTrackedRefStart =
@@ -657,6 +889,19 @@
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
interpState.debugIsMethodEntry = true;
#endif
+#if defined(WITH_JIT)
+ interpState.jitState = gDvmJit.pJitEntryTable ? kJitNormal : kJitOff;
+
+ /* Setup the Jit-to-interpreter entry points */
+ interpState.jitToInterpEntries = jitToInterpEntries;
+
+ /*
+ * Initialize the threshold filter [don't bother to zero out the
+ * actual table. We're looking for matches, and an occasional
+ * false positive is acceptible.
+ */
+ interpState.lastThreshFilter = 0;
+#endif
/*
* Initialize working state.
@@ -692,6 +937,14 @@
Interpreter stdInterp;
if (gDvm.executionMode == kExecutionModeInterpFast)
stdInterp = dvmMterpStd;
+#if defined(WITH_JIT)
+ else if (gDvm.executionMode == kExecutionModeJit)
+/* If profiling overhead can be kept low enough, we can use a profiling
+ * mterp fast for both Jit and "fast" modes. If overhead is too high,
+ * create a specialized profiling interpreter.
+ */
+ stdInterp = dvmMterpStd;
+#endif
else
stdInterp = dvmInterpretStd;
@@ -702,7 +955,7 @@
LOGVV("threadid=%d: interp STD\n", self->threadId);
change = (*stdInterp)(self, &interpState);
break;
-#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER) || defined(WITH_JIT)
case INTERP_DBG:
LOGVV("threadid=%d: interp DBG\n", self->threadId);
change = dvmInterpretDbg(self, &interpState);
@@ -715,4 +968,3 @@
*pResult = interpState.retval;
}
-
diff --git a/vm/interp/Interp.h b/vm/interp/Interp.h
index eb36b9f..cd4c7ec 100644
--- a/vm/interp/Interp.h
+++ b/vm/interp/Interp.h
@@ -26,6 +26,14 @@
void dvmInterpret(Thread* thread, const Method* method, JValue* pResult);
/*
+ * Throw an exception for a problem detected by the verifier.
+ *
+ * This is called from the handler for the throw-verification-error
+ * instruction. "method" is the method currently being executed.
+ */
+void dvmThrowVerificationError(const Method* method, int kind, int ref);
+
+/*
* Breakpoint optimization table.
*/
void dvmInitBreakpoints();
diff --git a/vm/interp/InterpDefs.h b/vm/interp/InterpDefs.h
index 856c2f5..23f1fe8 100644
--- a/vm/interp/InterpDefs.h
+++ b/vm/interp/InterpDefs.h
@@ -32,8 +32,48 @@
kInterpEntryInstr = 0, // continue to next instruction
kInterpEntryReturn = 1, // jump to method return
kInterpEntryThrow = 2, // jump to exception throw
+#if defined(WITH_JIT)
+ kInterpEntryResume = 3, // Resume after single-step
+#endif
} InterpEntry;
+#if defined(WITH_JIT)
+/*
+ * There are five entry points from the compiled code to the interpreter:
+ * 1) dvmJitToInterpNormal: find if there is a corresponding compilation for
+ * the new dalvik PC. If so, chain the originating compilation with the
+ * target then jump to it.
+ * 2) dvmJitToInterpInvokeNoChain: similar to 1) but don't chain. This is
+ * for handling 1-to-many mappings like virtual method call and
+ * packed switch.
+ * 3) dvmJitToInterpPunt: use the fast interpreter to execute the next
+ * instruction(s) and stay there as long as it is appropriate to return
+ * to the compiled land. This is used when the jit'ed code is about to
+ * throw an exception.
+ * 4) dvmJitToInterpSingleStep: use the portable interpreter to execute the
+ * next instruction only and return to pre-specified location in the
+ * compiled code to resume execution. This is mainly used as debugging
+ * feature to bypass problematic opcode implementations without
+ * disturbing the trace formation.
+ * 5) dvmJitToTraceSelect: if there is a single exit from a translation that
+ * has already gone hot enough to be translated, we should assume that
+ * the exit point should also be translated (this is a common case for
+ * invokes). This trace exit will first check for a chaining
+ * opportunity, and if none is available will switch to the debug
+ * interpreter immediately for trace selection (as if threshold had
+ * just been reached).
+ */
+struct JitToInterpEntries {
+ void *dvmJitToInterpNormal;
+ void *dvmJitToInterpNoChain;
+ void *dvmJitToInterpPunt;
+ void *dvmJitToInterpSingleStep;
+ void *dvmJitToTraceSelect;
+};
+
+#define JIT_TRACE_THRESH_FILTER_SIZE 16
+#endif
+
/*
* Interpreter context, used when switching from one interpreter to
* another. We also tuck "mterp" state in here.
@@ -78,8 +118,17 @@
* Interpreter switching.
*/
InterpEntry entryPoint; // what to do when we start
- int nextMode; // INTERP_STD or INTERP_DBG
+ int nextMode; // INTERP_STD, INTERP_DBG
+#if defined(WITH_JIT)
+ /*
+ * Local copies of field from gDvm placed here for fast access
+ */
+ unsigned char* pJitProfTable;
+ JitState jitState;
+ void* jitResume;
+ u2* jitResumePC;
+#endif
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
bool debugIsMethodEntry; // used for method entry event triggers
@@ -88,6 +137,19 @@
int debugTrackedRefStart; // tracked refs from prior invocations
#endif
+#if defined(WITH_JIT)
+ struct JitToInterpEntries jitToInterpEntries;
+
+ int currTraceRun;
+ int totalTraceLen; // Number of Dalvik insts in trace
+ const u2* currTraceHead; // Start of the trace we're building
+ const u2* currRunHead; // Start of run we're building
+ int currRunLen; // Length of run in 16-bit words
+ int lastThreshFilter;
+ u2* threshFilter[JIT_TRACE_THRESH_FILTER_SIZE];
+ JitTraceRun trace[MAX_JIT_RUN_LEN];
+#endif
+
} InterpState;
/*
@@ -123,7 +185,7 @@
/*
* Process fill-array-data.
*/
-bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,
+bool dvmInterpHandleFillArrayData(ArrayObject* arrayObject,
const u2* arrayData);
/*
@@ -145,4 +207,19 @@
;
}
+#if defined(WITH_JIT)
+/*
+ * Determine if the jit, debugger or profiler is currently active. Used when
+ * selecting which interpreter to switch to.
+ */
+static inline bool dvmJitDebuggerOrProfilerActive(int jitState)
+{
+ return jitState != kJitOff
+#if defined(WITH_PROFILER)
+ || gDvm.activeProfilers != 0
+#endif
+ ||gDvm.debuggerActive;
+}
+#endif
+
#endif /*_DALVIK_INTERP_DEFS*/
diff --git a/vm/interp/Jit.c b/vm/interp/Jit.c
new file mode 100644
index 0000000..7d922bb
--- /dev/null
+++ b/vm/interp/Jit.c
@@ -0,0 +1,694 @@
+/*
+ * 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.
+ */
+#ifdef WITH_JIT
+
+/*
+ * Target independent portion of Android's Jit
+ */
+
+#include "Dalvik.h"
+#include "Jit.h"
+
+
+#include "dexdump/OpCodeNames.h"
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <signal.h>
+#include "compiler/Compiler.h"
+#include "compiler/CompilerUtility.h"
+#include "compiler/CompilerIR.h"
+#include <errno.h>
+
+int dvmJitStartup(void)
+{
+ unsigned int i;
+ bool res = true; /* Assume success */
+
+ // Create the compiler thread and setup miscellaneous chores */
+ res &= dvmCompilerStartup();
+
+ dvmInitMutex(&gDvmJit.tableLock);
+ if (res && gDvm.executionMode == kExecutionModeJit) {
+ struct JitEntry *pJitTable = NULL;
+ unsigned char *pJitProfTable = NULL;
+ assert(gDvm.jitTableSize &&
+ !(gDvm.jitTableSize & (gDvmJit.jitTableSize - 1))); // Power of 2?
+ dvmLockMutex(&gDvmJit.tableLock);
+ pJitTable = (struct JitEntry*)
+ calloc(gDvmJit.jitTableSize, sizeof(*pJitTable));
+ if (!pJitTable) {
+ LOGE("jit table allocation failed\n");
+ res = false;
+ goto done;
+ }
+ /*
+ * NOTE: the profile table must only be allocated once, globally.
+ * Profiling is turned on and off by nulling out gDvm.pJitProfTable
+ * and then restoring its original value. However, this action
+ * is not syncronized for speed so threads may continue to hold
+ * and update the profile table after profiling has been turned
+ * off by null'ng the global pointer. Be aware.
+ */
+ pJitProfTable = (unsigned char *)malloc(JIT_PROF_SIZE);
+ if (!pJitProfTable) {
+ LOGE("jit prof table allocation failed\n");
+ res = false;
+ goto done;
+ }
+ memset(pJitProfTable,0,JIT_PROF_SIZE);
+ for (i=0; i < gDvmJit.jitTableSize; i++) {
+ pJitTable[i].chain = gDvmJit.jitTableSize;
+ }
+ /* Is chain field wide enough for termination pattern? */
+ assert(pJitTable[0].chain == gDvm.maxJitTableEntries);
+
+done:
+ gDvmJit.pJitEntryTable = pJitTable;
+ gDvmJit.jitTableMask = gDvmJit.jitTableSize - 1;
+ gDvmJit.jitTableEntriesUsed = 0;
+ gDvmJit.pProfTableCopy = gDvmJit.pProfTable = pJitProfTable;
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ }
+ return res;
+}
+
+/*
+ * If one of our fixed tables or the translation buffer fills up,
+ * call this routine to avoid wasting cycles on future translation requests.
+ */
+void dvmJitStopTranslationRequests()
+{
+ /*
+ * Note 1: This won't necessarily stop all translation requests, and
+ * operates on a delayed mechanism. Running threads look to the copy
+ * of this value in their private InterpState structures and won't see
+ * this change until it is refreshed (which happens on interpreter
+ * entry).
+ * Note 2: This is a one-shot memory leak on this table. Because this is a
+ * permanent off switch for Jit profiling, it is a one-time leak of 1K
+ * bytes, and no further attempt will be made to re-allocate it. Can't
+ * free it because some thread may be holding a reference.
+ */
+ gDvmJit.pProfTable = gDvmJit.pProfTableCopy = NULL;
+}
+
+#if defined(EXIT_STATS)
+/* Convenience function to increment counter from assembly code */
+void dvmBumpNoChain()
+{
+ gDvm.jitNoChainExit++;
+}
+
+/* Convenience function to increment counter from assembly code */
+void dvmBumpNormal()
+{
+ gDvm.jitNormalExit++;
+}
+
+/* Convenience function to increment counter from assembly code */
+void dvmBumpPunt(int from)
+{
+ gDvm.jitPuntExit++;
+}
+#endif
+
+/* Dumps profile info for a single trace */
+int dvmCompilerDumpTraceProfile(struct JitEntry *p)
+{
+ ChainCellCounts* pCellCounts;
+ char* traceBase;
+ u4* pExecutionCount;
+ u2* pCellOffset;
+ JitTraceDescription *desc;
+ const Method* method;
+
+ /*
+ * The codeAddress field has the low bit set to mark thumb
+ * mode. We need to strip that off before reconstructing the
+ * trace data. See the diagram in Assemble.c for more info
+ * on the trace layout in memory.
+ */
+ traceBase = (char*)p->codeAddress - 7;
+
+ if (p->codeAddress == NULL) {
+ LOGD("TRACEPROFILE 0x%08x 0 NULL 0 0", (int)traceBase);
+ return 0;
+ }
+
+ pExecutionCount = (u4*) (traceBase);
+ pCellOffset = (u2*) (traceBase + 4);
+ pCellCounts = (ChainCellCounts*) (traceBase + *pCellOffset);
+ desc = (JitTraceDescription*) ((char*)pCellCounts + sizeof(*pCellCounts));
+ method = desc->method;
+ LOGD("TRACEPROFILE 0x%08x % 10d %s%s [0x%x,%d]", (int)traceBase,
+ *pExecutionCount, method->clazz->descriptor, method->name,
+ desc->trace[0].frag.startOffset,
+ desc->trace[0].frag.numInsts);
+ return *pExecutionCount;
+}
+
+/* Dumps debugging & tuning stats to the log */
+void dvmJitStats()
+{
+ int i;
+ int hit;
+ int not_hit;
+ int chains;
+ if (gDvmJit.pJitEntryTable) {
+ for (i=0, chains=hit=not_hit=0;
+ i < (int) gDvmJit.jitTableSize;
+ i++) {
+ if (gDvmJit.pJitEntryTable[i].dPC != 0)
+ hit++;
+ else
+ not_hit++;
+ if (gDvmJit.pJitEntryTable[i].chain != gDvmJit.jitTableSize)
+ chains++;
+ }
+ LOGD(
+ "JIT: %d traces, %d slots, %d chains, %d maxQ, %d thresh, %s",
+ hit, not_hit + hit, chains, gDvmJit.compilerMaxQueued,
+ gDvmJit.threshold, gDvmJit.blockingMode ? "Blocking" : "Non-blocking");
+#if defined(EXIT_STATS)
+ LOGD(
+ "JIT: Lookups: %d hits, %d misses; %d NoChain, %d normal, %d punt",
+ gDvmJit.addrLookupsFound, gDvmJit.addrLookupsNotFound,
+ gDvmJit.noChainExit, gDvmJit.normalExit, gDvmJit.puntExit);
+#endif
+ LOGD("JIT: %d Translation chains", gDvmJit.translationChains);
+#if defined(INVOKE_STATS)
+ LOGD("JIT: Invoke: %d noOpt, %d chainable, %d return",
+ gDvmJit.invokeNoOpt, gDvmJit.invokeChain, gDvmJit.returnOp);
+#endif
+ if (gDvmJit.profile) {
+ int numTraces = 0;
+ long counts = 0;
+ for (i=0; i < (int) gDvmJit.jitTableSize; i++) {
+ if (gDvmJit.pJitEntryTable[i].dPC != 0) {
+ counts += dvmCompilerDumpTraceProfile( &gDvmJit.pJitEntryTable[i] );
+ numTraces++;
+ }
+ }
+ if (numTraces == 0)
+ numTraces = 1;
+ LOGD("JIT: Average execution count -> %d",(int)(counts / numTraces));
+ }
+ }
+}
+
+/*
+ * Final JIT shutdown. Only do this once, and do not attempt to restart
+ * the JIT later.
+ */
+void dvmJitShutdown(void)
+{
+ /* Shutdown the compiler thread */
+ dvmCompilerShutdown();
+
+ dvmCompilerDumpStats();
+
+ dvmDestroyMutex(&gDvmJit.tableLock);
+
+ if (gDvmJit.pJitEntryTable) {
+ free(gDvmJit.pJitEntryTable);
+ gDvmJit.pJitEntryTable = NULL;
+ }
+
+ if (gDvmJit.pProfTable) {
+ free(gDvmJit.pProfTable);
+ gDvmJit.pProfTable = NULL;
+ }
+}
+
+/*
+ * 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
+ * differently. In general, instructions are "proposed" to be added
+ * to the current trace prior to interpretation. If the interpreter
+ * then successfully completes the instruction, is will be considered
+ * part of the request. This allows us to examine machine state prior
+ * to interpretation, and also abort the trace request if the instruction
+ * throws or does something unexpected. However, return instructions
+ * will cause an immediate end to the translation request - which will
+ * be passed to the compiler before the return completes. This is done
+ * in response to special handling of returns by the interpreter (and
+ * because returns cannot throw in a way that causes problems for the
+ * translated code.
+ */
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState)
+{
+ int flags,i,len;
+ int switchInterp = false;
+ int debugOrProfile = (gDvm.debuggerActive || self->suspendCount
+#if defined(WITH_PROFILER)
+ || gDvm.activeProfilers
+#endif
+ );
+
+ switch (interpState->jitState) {
+ char* nopStr;
+ int target;
+ int offset;
+ DecodedInstruction decInsn;
+ case kJitTSelect:
+ dexDecodeInstruction(gDvm.instrFormat, pc, &decInsn);
+#if defined(SHOW_TRACE)
+ LOGD("TraceGen: adding %s",getOpcodeName(decInsn.opCode));
+#endif
+ flags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
+ len = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, pc);
+ offset = pc - interpState->method->insns;
+ if ((flags & kInstrNoJit) == kInstrNoJit) {
+ interpState->jitState = kJitTSelectEnd;
+ break;
+ } else {
+ if (pc != interpState->currRunHead + interpState->currRunLen) {
+ int currTraceRun;
+ /* We need to start a new trace run */
+ currTraceRun = ++interpState->currTraceRun;
+ interpState->currRunLen = 0;
+ interpState->currRunHead = (u2*)pc;
+ interpState->trace[currTraceRun].frag.startOffset = offset;
+ interpState->trace[currTraceRun].frag.numInsts = 0;
+ interpState->trace[currTraceRun].frag.runEnd = false;
+ interpState->trace[currTraceRun].frag.hint = kJitHintNone;
+ }
+ interpState->trace[interpState->currTraceRun].frag.numInsts++;
+ interpState->totalTraceLen++;
+ interpState->currRunLen += len;
+ if ( ((flags & kInstrUnconditional) == 0) &&
+ ((flags & (kInstrCanBranch |
+ kInstrCanSwitch |
+ kInstrCanReturn |
+ kInstrInvoke)) != 0)) {
+ interpState->jitState = kJitTSelectEnd;
+#if defined(SHOW_TRACE)
+ LOGD("TraceGen: ending on %s, basic block end",
+ getOpcodeName(decInsn.opCode));
+#endif
+ }
+ if (decInsn.opCode == OP_THROW) {
+ interpState->jitState = kJitTSelectEnd;
+ }
+ if (interpState->totalTraceLen >= JIT_MAX_TRACE_LEN) {
+ interpState->jitState = kJitTSelectEnd;
+ }
+ if (debugOrProfile) {
+ interpState->jitState = kJitTSelectAbort;
+ switchInterp = !debugOrProfile;
+ break;
+ }
+ if ((flags & kInstrCanReturn) != kInstrCanReturn) {
+ break;
+ }
+ }
+ /* NOTE: intentional fallthrough for returns */
+ case kJitTSelectEnd:
+ {
+ if (interpState->totalTraceLen == 0) {
+ switchInterp = !debugOrProfile;
+ break;
+ }
+ JitTraceDescription* desc =
+ (JitTraceDescription*)malloc(sizeof(JitTraceDescription) +
+ sizeof(JitTraceRun) * (interpState->currTraceRun+1));
+ if (desc == NULL) {
+ LOGE("Out of memory in trace selection");
+ dvmJitStopTranslationRequests();
+ interpState->jitState = kJitTSelectAbort;
+ switchInterp = !debugOrProfile;
+ break;
+ }
+ interpState->trace[interpState->currTraceRun].frag.runEnd =
+ true;
+ interpState->jitState = kJitNormal;
+ desc->method = interpState->method;
+ memcpy((char*)&(desc->trace[0]),
+ (char*)&(interpState->trace[0]),
+ sizeof(JitTraceRun) * (interpState->currTraceRun+1));
+#if defined(SHOW_TRACE)
+ LOGD("TraceGen: trace done, adding to queue");
+#endif
+ dvmCompilerWorkEnqueue(
+ interpState->currTraceHead,kWorkOrderTrace,desc);
+ if (gDvmJit.blockingMode) {
+ dvmCompilerDrainQueue();
+ }
+ switchInterp = !debugOrProfile;
+ }
+ break;
+ case kJitSingleStep:
+ interpState->jitState = kJitSingleStepEnd;
+ break;
+ case kJitSingleStepEnd:
+ interpState->entryPoint = kInterpEntryResume;
+ switchInterp = !debugOrProfile;
+ break;
+ case kJitTSelectAbort:
+#if defined(SHOW_TRACE)
+ LOGD("TraceGen: trace abort");
+#endif
+ interpState->jitState = kJitNormal;
+ switchInterp = !debugOrProfile;
+ break;
+ case kJitNormal:
+ break;
+ default:
+ dvmAbort();
+ }
+ return switchInterp;
+}
+
+static inline struct JitEntry *findJitEntry(const u2* pc)
+{
+ int idx = dvmJitHash(pc);
+
+ /* Expect a high hit rate on 1st shot */
+ if (gDvmJit.pJitEntryTable[idx].dPC == pc)
+ return &gDvmJit.pJitEntryTable[idx];
+ else {
+ int chainEndMarker = gDvmJit.jitTableSize;
+ while (gDvmJit.pJitEntryTable[idx].chain != chainEndMarker) {
+ idx = gDvmJit.pJitEntryTable[idx].chain;
+ if (gDvmJit.pJitEntryTable[idx].dPC == pc)
+ return &gDvmJit.pJitEntryTable[idx];
+ }
+ }
+ return NULL;
+}
+
+struct JitEntry *dvmFindJitEntry(const u2* pc)
+{
+ return findJitEntry(pc);
+}
+
+/*
+ * Allocate an entry in a JitTable. Assumes caller holds lock, if
+ * applicable. Normally used for table resizing. Will complain (die)
+ * if entry already exists in the table or if table is full.
+ */
+static struct JitEntry *allocateJitEntry(const u2* pc, struct JitEntry *table,
+ u4 size)
+{
+ struct JitEntry *p;
+ unsigned int idx;
+ unsigned int prev;
+ idx = dvmJitHashMask(pc, size-1);
+ while ((table[idx].chain != size) && (table[idx].dPC != pc)) {
+ idx = table[idx].chain;
+ }
+ assert(table[idx].dPC != pc); /* Already there */
+ if (table[idx].dPC == NULL) {
+ /* use this slot */
+ return &table[idx];
+ }
+ /* Find a free entry and chain it in */
+ prev = idx;
+ while (true) {
+ idx++;
+ if (idx == size)
+ idx = 0; /* Wraparound */
+ if ((table[idx].dPC == NULL) || (idx == prev))
+ break;
+ }
+ assert(idx != prev);
+ table[prev].chain = idx;
+ assert(table[idx].dPC == NULL);
+ return &table[idx];
+}
+
+/*
+ * If a translated code address exists for the davik byte code
+ * pointer return it. This routine needs to be fast.
+ */
+void* dvmJitGetCodeAddr(const u2* dPC)
+{
+ int idx = dvmJitHash(dPC);
+
+ /* If anything is suspended, don't re-enter the code cache */
+ if (gDvm.sumThreadSuspendCount > 0) {
+ return NULL;
+ }
+
+ /* Expect a high hit rate on 1st shot */
+ if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
+#if defined(EXIT_STATS)
+ gDvmJit.addrLookupsFound++;
+#endif
+ return gDvmJit.pJitEntryTable[idx].codeAddress;
+ } else {
+ int chainEndMarker = gDvmJit.jitTableSize;
+ while (gDvmJit.pJitEntryTable[idx].chain != chainEndMarker) {
+ idx = gDvmJit.pJitEntryTable[idx].chain;
+ if (gDvmJit.pJitEntryTable[idx].dPC == dPC) {
+#if defined(EXIT_STATS)
+ gDvmJit.addrLookupsFound++;
+#endif
+ return gDvmJit.pJitEntryTable[idx].codeAddress;
+ }
+ }
+ }
+#if defined(EXIT_STATS)
+ gDvmJit.addrLookupsNotFound++;
+#endif
+ return NULL;
+}
+
+/*
+ * Register the translated code pointer into the JitTable.
+ * NOTE: Once a codeAddress field transitions from NULL to
+ * JIT'd code, it must not be altered without first halting all
+ * threads.
+ */
+void dvmJitSetCodeAddr(const u2* dPC, void *nPC) {
+ struct JitEntry *jitEntry = findJitEntry(dPC);
+ assert(jitEntry);
+ /* Thumb code has odd PC */
+ jitEntry->codeAddress = (void *) ((intptr_t) nPC |1);
+}
+
+/*
+ * Determine if valid trace-bulding request is active. Return true
+ * if we need to abort and switch back to the fast interpreter, false
+ * otherwise. NOTE: may be called even when trace selection is not being
+ * requested
+ */
+
+#define PROFILE_STALENESS_THRESHOLD 100000LL
+bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState)
+{
+ bool res = false; /* Assume success */
+ int i;
+ if (gDvmJit.pJitEntryTable != NULL) {
+ /* Two-level filtering scheme */
+ for (i=0; i< JIT_TRACE_THRESH_FILTER_SIZE; i++) {
+ if (interpState->pc == interpState->threshFilter[i]) {
+ break;
+ }
+ }
+ if (i == JIT_TRACE_THRESH_FILTER_SIZE) {
+ /*
+ * Use random replacement policy - otherwise we could miss a large
+ * loop that contains more traces than the size of our filter array.
+ */
+ i = rand() % JIT_TRACE_THRESH_FILTER_SIZE;
+ interpState->threshFilter[i] = interpState->pc;
+ res = true;
+ }
+ /*
+ * If the compiler is backlogged, or if a debugger or profiler is
+ * active, cancel any JIT actions
+ */
+ if ( res || (gDvmJit.compilerQueueLength >= gDvmJit.compilerHighWater) ||
+ gDvm.debuggerActive || self->suspendCount
+#if defined(WITH_PROFILER)
+ || gDvm.activeProfilers
+#endif
+ ) {
+ if (interpState->jitState != kJitOff) {
+ interpState->jitState = kJitNormal;
+ }
+ } else if (interpState->jitState == kJitTSelectRequest) {
+ u4 chainEndMarker = gDvmJit.jitTableSize;
+ u4 idx = dvmJitHash(interpState->pc);
+
+ /* Walk the bucket chain to find an exact match for our PC */
+ while ((gDvmJit.pJitEntryTable[idx].chain != chainEndMarker) &&
+ (gDvmJit.pJitEntryTable[idx].dPC != interpState->pc)) {
+ idx = gDvmJit.pJitEntryTable[idx].chain;
+ }
+
+ if (gDvmJit.pJitEntryTable[idx].dPC == interpState->pc) {
+ /*
+ * Got a match. This means a trace has already
+ * been requested for this address. Bail back to
+ * mterp, which will check if the translation is ready
+ * for execution
+ */
+ interpState->jitState = kJitTSelectAbort;
+ } else {
+ /*
+ * No match. Aquire jitTableLock and find the last
+ * slot in the chain. Possibly continue the chain walk in case
+ * some other thread allocated the slot we were looking
+ * at previuosly
+ */
+ dvmLockMutex(&gDvmJit.tableLock);
+ /*
+ * At this point, if .dPC is NULL, then the slot we're
+ * looking at is the target slot from the primary hash
+ * (the simple, and expected case). Otherwise we're going
+ * to have to find a free slot and chain it.
+ */
+ MEM_BARRIER();
+ if (gDvmJit.pJitEntryTable[idx].dPC != NULL) {
+ u4 prev;
+ while (gDvmJit.pJitEntryTable[idx].chain != chainEndMarker) {
+ idx = gDvmJit.pJitEntryTable[idx].chain;
+ }
+ /* Here, idx should be pointing to the last cell of an
+ * active chain whose last member contains a valid dPC */
+ assert(gDvmJit.pJitEntryTable[idx].dPC != NULL);
+ /* Now, do a linear walk to find a free cell and add it to
+ * end of this chain */
+ prev = idx;
+ while (true) {
+ idx++;
+ if (idx == chainEndMarker)
+ idx = 0; /* Wraparound */
+ if ((gDvmJit.pJitEntryTable[idx].dPC == NULL) ||
+ (idx == prev))
+ break;
+ }
+ if (idx != prev) {
+ /* Got it - chain */
+ gDvmJit.pJitEntryTable[prev].chain = idx;
+ }
+ }
+ if (gDvmJit.pJitEntryTable[idx].dPC == NULL) {
+ /* Allocate the slot */
+ gDvmJit.pJitEntryTable[idx].dPC = interpState->pc;
+ gDvmJit.jitTableEntriesUsed++;
+ } else {
+ /*
+ * Table is full. We could resize it, but that would
+ * be better handled by the translator thread. It
+ * will be aware of how full the table is getting.
+ * Disable further profiling and continue.
+ */
+ interpState->jitState = kJitTSelectAbort;
+ LOGD("JIT: JitTable full, disabling profiling");
+ dvmJitStopTranslationRequests();
+ }
+ dvmUnlockMutex(&gDvmJit.tableLock);
+ }
+ }
+ switch (interpState->jitState) {
+ case kJitTSelectRequest:
+ interpState->jitState = kJitTSelect;
+ interpState->currTraceHead = interpState->pc;
+ interpState->currTraceRun = 0;
+ interpState->totalTraceLen = 0;
+ interpState->currRunHead = interpState->pc;
+ interpState->currRunLen = 0;
+ interpState->trace[0].frag.startOffset =
+ interpState->pc - interpState->method->insns;
+ interpState->trace[0].frag.numInsts = 0;
+ interpState->trace[0].frag.runEnd = false;
+ interpState->trace[0].frag.hint = kJitHintNone;
+ break;
+ case kJitTSelect:
+ case kJitTSelectAbort:
+ res = true;
+ case kJitSingleStep:
+ case kJitSingleStepEnd:
+ case kJitOff:
+ case kJitNormal:
+ break;
+ default:
+ dvmAbort();
+ }
+ }
+ return res;
+}
+
+/*
+ * Resizes the JitTable. Must be a power of 2, and returns true on failure.
+ * Stops all threads, and thus is a heavyweight operation.
+ */
+bool dvmJitResizeJitTable( unsigned int size )
+{
+ struct JitEntry *pNewTable;
+ u4 newMask;
+ unsigned int i;
+
+ assert(gDvm.pJitEntryTable != NULL);
+ assert(size && !(size & (size - 1))); /* Is power of 2? */
+
+ LOGD("Jit: resizing JitTable from %d to %d", gDvmJit.jitTableSize, size);
+
+ newMask = size - 1;
+
+ if (size <= gDvmJit.jitTableSize) {
+ return true;
+ }
+
+ pNewTable = (struct JitEntry*)calloc(size, sizeof(*pNewTable));
+ if (pNewTable == NULL) {
+ return true;
+ }
+ for (i=0; i< size; i++) {
+ pNewTable[i].chain = size; /* Initialize chain termination */
+ }
+
+ /* Stop all other interpreting/jit'ng threads */
+ dvmSuspendAllThreads(SUSPEND_FOR_JIT);
+
+ /*
+ * At this point, only the compiler thread may be in contention
+ * for the jitEntryTable (it is not affected by the thread suspension).
+ * Aquire the lock.
+ */
+
+ dvmLockMutex(&gDvmJit.tableLock);
+
+ for (i=0; i < gDvmJit.jitTableSize; i++) {
+ if (gDvmJit.pJitEntryTable[i].dPC) {
+ struct JitEntry *p;
+ p = allocateJitEntry(gDvmJit.pJitEntryTable[i].dPC,
+ pNewTable, size);
+ p->dPC = gDvmJit.pJitEntryTable[i].dPC;
+ p->codeAddress = gDvmJit.pJitEntryTable[i].codeAddress;
+ }
+ }
+
+ free(gDvmJit.pJitEntryTable);
+ gDvmJit.pJitEntryTable = pNewTable;
+ gDvmJit.jitTableSize = size;
+ gDvmJit.jitTableMask = size - 1;
+
+ dvmUnlockMutex(&gDvmJit.tableLock);
+
+ /* Restart the world */
+ dvmResumeAllThreads(SUSPEND_FOR_JIT);
+
+ return false;
+}
+
+
+#endif /* WITH_JIT */
diff --git a/vm/interp/Jit.h b/vm/interp/Jit.h
new file mode 100644
index 0000000..5d748d5
--- /dev/null
+++ b/vm/interp/Jit.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+/*
+ * Jit control
+ */
+#ifndef _DALVIK_INTERP_JIT
+#define _DALVIK_INTERP_JIT
+
+#include "InterpDefs.h"
+
+#define JIT_PROF_SIZE 512
+
+#define JIT_MAX_TRACE_LEN 100
+
+/*
+ * JitTable hash function.
+ */
+
+static inline u4 dvmJitHashMask( const u2* p, u4 mask ) {
+ return ((((u4)p>>12)^(u4)p)>>1) & (mask);
+}
+
+static inline u4 dvmJitHash( const u2* p ) {
+ return dvmJitHashMask( p, gDvmJit.jitTableMask );
+}
+
+
+
+/*
+ * Entries in the JIT's address lookup hash table.
+ * with assembly hash function in mterp.
+ * TODO: rework this structure now that the profile counts have
+ * moved into their own table.
+ */
+typedef struct JitEntry {
+ u2 unused; /* was execution count */
+ u2 chain; /* Index of next in chain */
+ const u2* dPC; /* Dalvik code address */
+ void* codeAddress; /* Code address of native translation */
+} JitEntry;
+
+int dvmJitStartup(void);
+void dvmJitShutdown(void);
+int dvmCheckJit(const u2* pc, Thread* self, InterpState* interpState);
+void* dvmJitGetCodeAddr(const u2* dPC);
+void dvmJitSetCodeAddr(const u2* dPC, void *nPC);
+bool dvmJitCheckTraceRequest(Thread* self, InterpState* interpState);
+void* dvmJitChain(void* tgtAddr, u4* branchAddr);
+void dvmJitStopTranslationRequests(void);
+void dvmJitStats(void);
+bool dvmJitResizeJitTable(unsigned int size);
+struct JitEntry *dvmFindJitEntry(const u2* pc);
+
+
+#endif /*_DALVIK_INTERP_JIT*/
diff --git a/vm/interp/Stack.c b/vm/interp/Stack.c
index d5c5fe9..730b1a8 100644
--- a/vm/interp/Stack.c
+++ b/vm/interp/Stack.c
@@ -76,9 +76,10 @@
if (stackPtr - stackReq < self->interpStackEnd) {
/* not enough space */
- LOGW("Stack overflow on call to interp (top=%p cur=%p size=%d %s.%s)\n",
- self->interpStackStart, self->curFrame, self->interpStackSize,
- method->clazz->descriptor, method->name);
+ LOGW("Stack overflow on call to interp "
+ "(req=%d top=%p cur=%p size=%d %s.%s)\n",
+ stackReq, self->interpStackStart, self->curFrame,
+ self->interpStackSize, method->clazz->descriptor, method->name);
dvmHandleStackOverflow(self);
assert(dvmCheckException(self));
return false;
@@ -148,9 +149,10 @@
if (stackPtr - stackReq < self->interpStackEnd) {
/* not enough space */
- LOGW("Stack overflow on call to native (top=%p cur=%p size=%d '%s')\n",
- self->interpStackStart, self->curFrame, self->interpStackSize,
- method->name);
+ LOGW("Stack overflow on call to native "
+ "(req=%d top=%p cur=%p size=%d '%s')\n",
+ stackReq, self->interpStackStart, self->curFrame,
+ self->interpStackSize, method->name);
dvmHandleStackOverflow(self);
assert(dvmCheckException(self));
return false;
@@ -217,9 +219,10 @@
if (stackPtr - stackReq < self->interpStackEnd) {
/* not enough space; let JNI throw the exception */
- LOGW("Stack overflow on PushLocal (top=%p cur=%p size=%d '%s')\n",
- self->interpStackStart, self->curFrame, self->interpStackSize,
- method->name);
+ LOGW("Stack overflow on PushLocal "
+ "(req=%d top=%p cur=%p size=%d '%s')\n",
+ stackReq, self->interpStackStart, self->curFrame,
+ self->interpStackSize, method->name);
dvmHandleStackOverflow(self);
assert(dvmCheckException(self));
return false;
@@ -505,11 +508,17 @@
//dvmDumpThreadStack(dvmThreadSelf());
if (dvmIsNativeMethod(method)) {
+#ifdef WITH_PROFILER
+ TRACE_METHOD_ENTER(self, method);
+#endif
/*
* Because we leave no space for local variables, "curFrame" points
* directly at the method arguments.
*/
(*method->nativeFunc)(self->curFrame, pResult, method, self);
+#ifdef WITH_PROFILER
+ TRACE_METHOD_EXIT(self, method);
+#endif
} else {
dvmInterpret(self, method, pResult);
}
@@ -609,11 +618,17 @@
#endif
if (dvmIsNativeMethod(method)) {
+#ifdef WITH_PROFILER
+ TRACE_METHOD_ENTER(self, method);
+#endif
/*
* Because we leave no space for local variables, "curFrame" points
* directly at the method arguments.
*/
(*method->nativeFunc)(self->curFrame, pResult, method, self);
+#ifdef WITH_PROFILER
+ TRACE_METHOD_EXIT(self, method);
+#endif
} else {
dvmInterpret(self, method, pResult);
}
@@ -713,11 +728,17 @@
//dvmDumpThreadStack(dvmThreadSelf());
if (dvmIsNativeMethod(method)) {
+#ifdef WITH_PROFILER
+ TRACE_METHOD_ENTER(self, method);
+#endif
/*
* Because we leave no space for local variables, "curFrame" points
* directly at the method arguments.
*/
(*method->nativeFunc)(self->curFrame, &retval, method, self);
+#ifdef WITH_PROFILER
+ TRACE_METHOD_EXIT(self, method);
+#endif
} else {
dvmInterpret(self, method, &retval);
}
diff --git a/vm/interp/Stack.h b/vm/interp/Stack.h
index 1b28d49..f2a481b 100644
--- a/vm/interp/Stack.h
+++ b/vm/interp/Stack.h
@@ -146,6 +146,8 @@
const u2* currentPc;
} xtra;
+ /* Native return pointer for JIT, or 0 if interpreted */
+ const u2* returnAddr;
#ifdef PAD_SAVE_AREA
u4 pad3, pad4, pad5;
#endif
diff --git a/vm/jdwp/JdwpAdb.c b/vm/jdwp/JdwpAdb.c
index 317c209..a74f9e1 100644
--- a/vm/jdwp/JdwpAdb.c
+++ b/vm/jdwp/JdwpAdb.c
@@ -49,6 +49,7 @@
int controlSock;
int clientSock;
bool awaitingHandshake;
+ bool shuttingDown;
int wakeFds[2];
int inputCount;
@@ -129,6 +130,13 @@
return true;
}
+/*
+ * Receive a file descriptor from ADB. The fd can be used to communicate
+ * directly with a debugger or DDMS.
+ *
+ * Returns the file descriptor on success. On failure, returns -1 and
+ * closes netState->controlSock.
+ */
static int receiveClientFd(JdwpNetState* netState)
{
struct msghdr msg;
@@ -161,9 +169,15 @@
ret = recvmsg(netState->controlSock, &msg, 0);
} while (ret < 0 && errno == EINTR);
- if (ret < 0) {
- LOGE("receiving file descriptor from ADB failed (socket %d): %s\n",
- netState->controlSock, strerror(errno));
+ if (ret <= 0) {
+ if (ret < 0) {
+ LOGW("receiving file descriptor from ADB failed (socket %d): %s\n",
+ netState->controlSock, strerror(errno));
+ } else {
+ LOGI("adbd disconnected\n");
+ }
+ close(netState->controlSock);
+ netState->controlSock = -1;
return -1;
}
@@ -180,11 +194,15 @@
static bool acceptConnection(struct JdwpState* state)
{
JdwpNetState* netState = state->netState;
+ int retryCount = 0;
/* first, ensure that we get a connection to the ADB daemon */
- if (netState->controlSock < 0)
- {
+retry:
+ if (netState->shuttingDown)
+ return false;
+
+ if (netState->controlSock < 0) {
int sleep_ms = 500;
const int sleep_max_ms = 2*1000;
char buff[5];
@@ -205,6 +223,19 @@
buff[4] = 0;
for (;;) {
+ /*
+ * If adbd isn't running, because USB debugging was disabled or
+ * perhaps the system is restarting it for "adb root", the
+ * connect() will fail. We loop here forever waiting for it
+ * to come back.
+ *
+ * Waking up and polling every couple of seconds is generally a
+ * bad thing to do, but we only do this if the application is
+ * debuggable *and* adbd isn't running. Still, for the sake
+ * of battery life, we should consider timing out and giving
+ * up after a few minutes in case somebody ships an app with
+ * the debuggable flag set.
+ */
int ret = connect(netState->controlSock,
&netState->controlAddr.controlAddrPlain,
netState->controlAddrLen);
@@ -237,12 +268,21 @@
LOGV("trying to receive file descriptor from ADB\n");
/* now we can receive a client file descriptor */
netState->clientSock = receiveClientFd(netState);
- if (netState->clientSock >= 0) {
- LOGI("received file descriptor %d from ADB\n", netState->clientSock);
+ if (netState->shuttingDown)
+ return false; // suppress logs and additional activity
+
+ if (netState->clientSock < 0) {
+ if (++retryCount > 5) {
+ LOGE("adb connection max retries exceeded\n");
+ return false;
+ }
+ goto retry;
+ } else {
+ LOGV("received file descriptor %d from ADB\n", netState->clientSock);
netState->awaitingHandshake = 1;
netState->inputCount = 0;
+ return true;
}
- return (netState->clientSock >= 0);
}
/*
@@ -287,6 +327,8 @@
if (netState == NULL)
return;
+ netState->shuttingDown = true;
+
clientSock = netState->clientSock;
if (clientSock >= 0) {
shutdown(clientSock, SHUT_RDWR);
@@ -536,12 +578,18 @@
if (netState->controlSock >= 0 &&
FD_ISSET(netState->controlSock, &readfds))
{
- LOGI("Ignoring second debugger -- accepting and dropping\n");
int sock = receiveClientFd(netState);
- if (sock < 0)
- LOGI("Weird -- client fd reception failed\n");
- else
+ if (sock >= 0) {
+ LOGI("Ignoring second debugger -- accepting and dropping\n");
close(sock);
+ } else {
+ assert(netState->controlSock < 0);
+ /*
+ * Remote side most likely went away, so our next read
+ * on netState->clientSock will fail and throw us out
+ * of the loop.
+ */
+ }
}
if (netState->clientSock >= 0 &&
FD_ISSET(netState->clientSock, &readfds))
@@ -557,7 +605,7 @@
return true;
} else if (readCount == 0) {
/* EOF hit -- far end went away */
- LOGD("+++ peer disconnected\n");
+ LOGV("+++ peer disconnected\n");
goto fail;
} else
break;
diff --git a/vm/mterp/Mterp.c b/vm/mterp/Mterp.c
index 53ddeb4..60e2de8 100644
--- a/vm/mterp/Mterp.c
+++ b/vm/mterp/Mterp.c
@@ -77,6 +77,9 @@
glue->interpStackEnd = self->interpStackEnd;
glue->pSelfSuspendCount = &self->suspendCount;
+#if defined(WITH_JIT)
+ glue->pJitProfTable = gDvmJit.pProfTable;
+#endif
#if defined(WITH_DEBUGGER)
glue->pDebuggerActive = &gDvm.debuggerActive;
#endif
@@ -111,4 +114,3 @@
return true;
}
}
-
diff --git a/vm/mterp/Mterp.h b/vm/mterp/Mterp.h
index ae2d207..8b3f7b4 100644
--- a/vm/mterp/Mterp.h
+++ b/vm/mterp/Mterp.h
@@ -22,6 +22,9 @@
#include "Dalvik.h"
#include "interp/InterpDefs.h"
+#if defined(WITH_JIT)
+#include "interp/Jit.h"
+#endif
/*
* Interpreter state, passed into C functions from assembly stubs. The
diff --git a/vm/mterp/arm-vfp/OP_ADD_DOUBLE.S b/vm/mterp/arm-vfp/OP_ADD_DOUBLE.S
new file mode 100644
index 0000000..5a5ad1d
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_ADD_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide.S" {"instr":"faddd d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/arm-vfp/OP_ADD_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..9823765
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_ADD_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide2addr.S" {"instr":"faddd d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_ADD_FLOAT.S b/vm/mterp/arm-vfp/OP_ADD_FLOAT.S
new file mode 100644
index 0000000..22023ec
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_ADD_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop.S" {"instr":"fadds s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/arm-vfp/OP_ADD_FLOAT_2ADDR.S
new file mode 100644
index 0000000..e787589
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_ADD_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop2addr.S" {"instr":"fadds s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S b/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S
new file mode 100644
index 0000000..a8c3ea4
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPG_DOUBLE.S
@@ -0,0 +1,43 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ fldd d0, [r2] @ d0<- vBB
+ fldd d1, [r3] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mov r0, #1 @ r0<- 1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .L${opcode}_finish @ argh
+
+%break
+.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
new file mode 100644
index 0000000..4c14fbb
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPG_FLOAT.S
@@ -0,0 +1,43 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ flds s0, [r2] @ s0<- vBB
+ flds s1, [r3] @ s1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mov r0, #1 @ r0<- 1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .L${opcode}_finish @ argh
+
+%break
+.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
new file mode 100644
index 0000000..999faee
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPL_DOUBLE.S
@@ -0,0 +1,43 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ fldd d0, [r2] @ d0<- vBB
+ fldd d1, [r3] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mvn r0, #0 @ r0<- -1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r1<- 1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .L${opcode}_finish @ argh
+
+%break
+.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
new file mode 100644
index 0000000..9b2133c
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_CMPL_FLOAT.S
@@ -0,0 +1,43 @@
+%verify "executed"
+%verify "basic lt, gt, eq */
+%verify "left arg NaN"
+%verify "right arg NaN"
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ flds s0, [r2] @ s0<- vBB
+ flds s1, [r3] @ s1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mvn r0, #0 @ r0<- -1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r1<- 1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .L${opcode}_finish @ argh
+
+%break
+.L${opcode}_finish:
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
diff --git a/vm/mterp/arm-vfp/OP_DIV_DOUBLE.S b/vm/mterp/arm-vfp/OP_DIV_DOUBLE.S
new file mode 100644
index 0000000..11770ad
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_DIV_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide.S" {"instr":"fdivd d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_DIV_DOUBLE_2ADDR.S b/vm/mterp/arm-vfp/OP_DIV_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..a52f434
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_DIV_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide2addr.S" {"instr":"fdivd d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_DIV_FLOAT.S b/vm/mterp/arm-vfp/OP_DIV_FLOAT.S
new file mode 100644
index 0000000..2e82ada
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_DIV_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop.S" {"instr":"fdivs s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/arm-vfp/OP_DIV_FLOAT_2ADDR.S
new file mode 100644
index 0000000..2147583
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_DIV_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop2addr.S" {"instr":"fdivs s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/arm-vfp/OP_DOUBLE_TO_FLOAT.S
new file mode 100644
index 0000000..33d5b61
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_DOUBLE_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/funopNarrower.S" {"instr":"fcvtsd s0, d0"}
diff --git a/vm/mterp/arm-vfp/OP_DOUBLE_TO_INT.S b/vm/mterp/arm-vfp/OP_DOUBLE_TO_INT.S
new file mode 100644
index 0000000..2ef4838
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/funopNarrower.S" {"instr":"ftosizd s0, d0"}
diff --git a/vm/mterp/arm-vfp/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/arm-vfp/OP_FLOAT_TO_DOUBLE.S
new file mode 100644
index 0000000..0acb3d8
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_FLOAT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/funopWider.S" {"instr":"fcvtds d0, s0"}
diff --git a/vm/mterp/arm-vfp/OP_FLOAT_TO_INT.S b/vm/mterp/arm-vfp/OP_FLOAT_TO_INT.S
new file mode 100644
index 0000000..d0a9a2e
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_FLOAT_TO_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/funop.S" {"instr":"ftosizs s1, s0"}
diff --git a/vm/mterp/arm-vfp/OP_INT_TO_DOUBLE.S b/vm/mterp/arm-vfp/OP_INT_TO_DOUBLE.S
new file mode 100644
index 0000000..6eb430e
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_INT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/funopWider.S" {"instr":"fsitod d0, s0"}
diff --git a/vm/mterp/arm-vfp/OP_INT_TO_FLOAT.S b/vm/mterp/arm-vfp/OP_INT_TO_FLOAT.S
new file mode 100644
index 0000000..698bdc7
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_INT_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/funop.S" {"instr":"fsitos s1, s0"}
diff --git a/vm/mterp/arm-vfp/OP_MUL_DOUBLE.S b/vm/mterp/arm-vfp/OP_MUL_DOUBLE.S
new file mode 100644
index 0000000..7563191
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_MUL_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide.S" {"instr":"fmuld d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_MUL_DOUBLE_2ADDR.S b/vm/mterp/arm-vfp/OP_MUL_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..eadf101
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_MUL_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide2addr.S" {"instr":"fmuld d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_MUL_FLOAT.S b/vm/mterp/arm-vfp/OP_MUL_FLOAT.S
new file mode 100644
index 0000000..bb3ab42
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_MUL_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop.S" {"instr":"fmuls s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/arm-vfp/OP_MUL_FLOAT_2ADDR.S
new file mode 100644
index 0000000..3918537
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_MUL_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop2addr.S" {"instr":"fmuls s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_SUB_DOUBLE.S b/vm/mterp/arm-vfp/OP_SUB_DOUBLE.S
new file mode 100644
index 0000000..d40e083
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_SUB_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide.S" {"instr":"fsubd d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_SUB_DOUBLE_2ADDR.S b/vm/mterp/arm-vfp/OP_SUB_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..705124f
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_SUB_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinopWide2addr.S" {"instr":"fsubd d2, d0, d1"}
diff --git a/vm/mterp/arm-vfp/OP_SUB_FLOAT.S b/vm/mterp/arm-vfp/OP_SUB_FLOAT.S
new file mode 100644
index 0000000..0bf2bc0
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_SUB_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop.S" {"instr":"fsubs s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/arm-vfp/OP_SUB_FLOAT_2ADDR.S
new file mode 100644
index 0000000..e214068
--- /dev/null
+++ b/vm/mterp/arm-vfp/OP_SUB_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "arm-vfp/fbinop2addr.S" {"instr":"fsubs s2, s0, s1"}
diff --git a/vm/mterp/arm-vfp/README.txt b/vm/mterp/arm-vfp/README.txt
new file mode 100644
index 0000000..5201bbe
--- /dev/null
+++ b/vm/mterp/arm-vfp/README.txt
@@ -0,0 +1,5 @@
+Instruction handlers that take advantage of ARM VFP. These work with VFP
+v2 and v3 (VFPLite).
+
+The ARM code driving the floating-point calculations will run on ARMv5TE
+and later.
diff --git a/vm/mterp/arm-vfp/fbinop.S b/vm/mterp/arm-vfp/fbinop.S
new file mode 100644
index 0000000..ff9683e
--- /dev/null
+++ b/vm/mterp/arm-vfp/fbinop.S
@@ -0,0 +1,23 @@
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ $instr @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/arm-vfp/fbinop2addr.S b/vm/mterp/arm-vfp/fbinop2addr.S
new file mode 100644
index 0000000..85b9fab
--- /dev/null
+++ b/vm/mterp/arm-vfp/fbinop2addr.S
@@ -0,0 +1,21 @@
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ $instr @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/arm-vfp/fbinopWide.S b/vm/mterp/arm-vfp/fbinopWide.S
new file mode 100644
index 0000000..2b9ad69
--- /dev/null
+++ b/vm/mterp/arm-vfp/fbinopWide.S
@@ -0,0 +1,23 @@
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ $instr @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/arm-vfp/fbinopWide2addr.S b/vm/mterp/arm-vfp/fbinopWide2addr.S
new file mode 100644
index 0000000..15d9424
--- /dev/null
+++ b/vm/mterp/arm-vfp/fbinopWide2addr.S
@@ -0,0 +1,22 @@
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ $instr @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/arm-vfp/funop.S b/vm/mterp/arm-vfp/funop.S
new file mode 100644
index 0000000..a5846ce
--- /dev/null
+++ b/vm/mterp/arm-vfp/funop.S
@@ -0,0 +1,18 @@
+ /*
+ * Generic 32-bit unary floating-point operation. Provide an "instr"
+ * line that specifies an instruction that performs "s1 = op s0".
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ $instr @ s1<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s1, [r9] @ vA<- s1
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/arm-vfp/funopNarrower.S b/vm/mterp/arm-vfp/funopNarrower.S
new file mode 100644
index 0000000..7ae1676
--- /dev/null
+++ b/vm/mterp/arm-vfp/funopNarrower.S
@@ -0,0 +1,18 @@
+ /*
+ * Generic 64bit-to-32bit unary floating point operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ fldd d0, [r3] @ d0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ $instr @ s0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s0, [r9] @ vA<- s0
+ GOTO_OPCODE(ip) @ jump to next instruction
diff --git a/vm/mterp/arm-vfp/funopWider.S b/vm/mterp/arm-vfp/funopWider.S
new file mode 100644
index 0000000..055b851
--- /dev/null
+++ b/vm/mterp/arm-vfp/funopWider.S
@@ -0,0 +1,18 @@
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ $instr @ d0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fstd d0, [r9] @ vA<- d0
+ 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 db5a5d8..2cf88f0 100644
--- a/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_INT.S
@@ -14,20 +14,23 @@
*/
d2i_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
- ldr r2, .L${opcode}_maxlo @ (double)maxint, lo
- ldr r3, .L${opcode}_maxhi @ (double)maxint, hi
+ mov r2, #0x80000000 @ maxint, as a double (low word)
+ mov r2, r2, asr #9 @ 0xffc00000
sub sp, sp, #4 @ align for EABI
- mov r4, r0 @ save r0
+ mvn r3, #0xbe000000 @ maxint, as a double (high word)
+ sub r3, r3, #0x00200000 @ 0x41dfffff
+ mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxint?
cmp r0, #0 @ nonzero == yes
- mvnne r0, #0x80000000 @ return maxint (7fffffff)
+ mvnne r0, #0x80000000 @ return maxint (0x7fffffff)
bne 1f
mov r0, r4 @ recover arg
mov r1, r5
- ldr r3, .L${opcode}_min @ (double)minint, hi
- mov r2, #0 @ (double)minint, lo
+ mov r3, #0xc1000000 @ minint, as a double (high word)
+ add r3, r3, #0x00e00000 @ 0xc1e00000
+ mov r2, #0 @ minint, as a double (low word)
bl __aeabi_dcmple @ is arg <= minint?
cmp r0, #0 @ nonzero == yes
movne r0, #0x80000000 @ return minint (80000000)
@@ -48,12 +51,5 @@
1:
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
-.L${opcode}_maxlo:
- .word 0xffc00000 @ maxint, as a double (low word)
-.L${opcode}_maxhi:
- .word 0x41dfffff @ maxint, as a double (high word)
-.L${opcode}_min:
- .word 0xc1e00000 @ minint, as a double (high word)
#endif
diff --git a/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S b/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
index 1d274e9..563027d 100644
--- a/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
+++ b/vm/mterp/armv5te/OP_DOUBLE_TO_LONG.S
@@ -12,10 +12,11 @@
*/
d2l_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
- ldr r3, .L${opcode}_max @ (double)maxlong, hi
+ mov r3, #0x43000000 @ maxlong, as a double (high word)
+ add r3, #0x00e00000 @ 0x43e00000
+ mov r2, #0 @ maxlong, as a double (low word)
sub sp, sp, #4 @ align for EABI
- mov r2, #0 @ (double)maxlong, lo
- mov r4, r0 @ save r0
+ mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxlong?
cmp r0, #0 @ nonzero == yes
@@ -25,8 +26,9 @@
mov r0, r4 @ recover arg
mov r1, r5
- ldr r3, .L${opcode}_min @ (double)minlong, hi
- mov r2, #0 @ (double)minlong, lo
+ mov r3, #0xc3000000 @ minlong, as a double (high word)
+ add r3, #0x00e00000 @ 0xc3e00000
+ mov r2, #0 @ minlong, as a double (low word)
bl __aeabi_dcmple @ is arg <= minlong?
cmp r0, #0 @ nonzero == yes
movne r0, #0 @ return minlong (8000000000000000)
@@ -50,8 +52,3 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-.L${opcode}_max:
- .word 0x43e00000 @ maxlong, as a double (high word)
-.L${opcode}_min:
- .word 0xc3e00000 @ minlong, as a double (high word)
-
diff --git a/vm/mterp/armv5te/OP_GOTO.S b/vm/mterp/armv5te/OP_GOTO.S
index 3433a73..26f0c8f 100644
--- a/vm/mterp/armv5te/OP_GOTO.S
+++ b/vm/mterp/armv5te/OP_GOTO.S
@@ -11,7 +11,15 @@
movs r9, r0, asr #24 @ r9<- ssssssAA (sign-extended)
mov r9, r9, lsl #1 @ r9<- byte offset
bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
+#endif
diff --git a/vm/mterp/armv5te/OP_GOTO_16.S b/vm/mterp/armv5te/OP_GOTO_16.S
index 479438e..f738a98 100644
--- a/vm/mterp/armv5te/OP_GOTO_16.S
+++ b/vm/mterp/armv5te/OP_GOTO_16.S
@@ -10,7 +10,16 @@
FETCH_S(r0, 1) @ r0<- ssssAAAA (sign-extended)
movs r9, r0, asl #1 @ r9<- byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
diff --git a/vm/mterp/armv5te/OP_GOTO_32.S b/vm/mterp/armv5te/OP_GOTO_32.S
index 617b8ba..17780b9 100644
--- a/vm/mterp/armv5te/OP_GOTO_32.S
+++ b/vm/mterp/armv5te/OP_GOTO_32.S
@@ -18,7 +18,15 @@
orrs r0, r0, r1, lsl #16 @ r0<- AAAAaaaa, check sign
mov r9, r0, asl #1 @ r9<- byte offset
ble common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
+#endif
diff --git a/vm/mterp/armv5te/OP_MONITOR_ENTER.S b/vm/mterp/armv5te/OP_MONITOR_ENTER.S
index 6d4c2d8..524621a 100644
--- a/vm/mterp/armv5te/OP_MONITOR_ENTER.S
+++ b/vm/mterp/armv5te/OP_MONITOR_ENTER.S
@@ -8,9 +8,7 @@
GET_VREG(r1, r2) @ r1<- vAA (object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
cmp r1, #0 @ null object?
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC() @ export PC so we can grab stack trace
-#endif
+ EXPORT_PC() @ need for precise GC, MONITOR_TRACKING
beq common_errNullObject @ null object, throw an exception
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
bl dvmLockObject @ call(self, obj)
diff --git a/vm/mterp/armv5te/OP_MOVE_WIDE_16.S b/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
index 1e0b5f2..88d996f 100644
--- a/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
+++ b/vm/mterp/armv5te/OP_MOVE_WIDE_16.S
@@ -6,7 +6,7 @@
add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
add r2, rFP, r2, lsl #2 @ r2<- &fp[AAAA]
ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
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_NEW_INSTANCE.S b/vm/mterp/armv5te/OP_NEW_INSTANCE.S
index d1d2df6..639d9c6 100644
--- a/vm/mterp/armv5te/OP_NEW_INSTANCE.S
+++ b/vm/mterp/armv5te/OP_NEW_INSTANCE.S
@@ -22,16 +22,13 @@
cmp r1, #CLASS_INITIALIZED @ has class been initialized?
bne .L${opcode}_needinit @ no, init class now
.L${opcode}_initialized: @ r0=class
- ldr r3, [r0, #offClassObject_accessFlags] @ r3<- clazz->accessFlags
- tst r3, #(ACC_INTERFACE|ACC_ABSTRACT) @ abstract or interface?
mov r1, #ALLOC_DONT_TRACK @ flags for alloc call
- beq .L${opcode}_finish @ concrete class, continue
- b .L${opcode}_abstract @ fail
+ bl dvmAllocObject @ r0<- new object
+ b .L${opcode}_finish @ continue
%break
.balign 32 @ minimize cache lines
-.L${opcode}_finish: @ r0=class
- bl dvmAllocObject @ r0<- new object
+.L${opcode}_finish: @ r0=new object
mov r3, rINST, lsr #8 @ r3<- AA
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle the exception
@@ -67,18 +64,6 @@
bne .L${opcode}_resolved @ no, continue
b common_exceptionThrown @ yes, handle exception
- /*
- * We can't instantiate an abstract class or interface, so throw an
- * InstantiationError with the class descriptor as the message.
- *
- * r0 holds class object
- */
-.L${opcode}_abstract:
- ldr r1, [r0, #offClassObject_descriptor]
- ldr r0, .LstrInstantiationErrorPtr
- bl dvmThrowExceptionWithClassMessage
- b common_exceptionThrown
-
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
diff --git a/vm/mterp/armv5te/OP_PACKED_SWITCH.S b/vm/mterp/armv5te/OP_PACKED_SWITCH.S
index 6fde05b..72e742a 100644
--- a/vm/mterp/armv5te/OP_PACKED_SWITCH.S
+++ b/vm/mterp/armv5te/OP_PACKED_SWITCH.S
@@ -20,7 +20,16 @@
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
diff --git a/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
new file mode 100644
index 0000000..0ed928b
--- /dev/null
+++ b/vm/mterp/armv5te/OP_THROW_VERIFICATION_ERROR.S
@@ -0,0 +1,14 @@
+%verify executed
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ FETCH(r2, 1) @ r2<- BBBB
+ EXPORT_PC() @ export the PC
+ mov r1, rINST, lsr #8 @ r1<- AA
+ bl dvmThrowVerificationError @ always throws
+ b common_exceptionThrown @ handle exception
+
diff --git a/vm/mterp/armv5te/OP_UNUSED_ED.S b/vm/mterp/armv5te/OP_UNUSED_ED.S
deleted file mode 100644
index faa7246..0000000
--- a/vm/mterp/armv5te/OP_UNUSED_ED.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "armv5te/unused.S"
diff --git a/vm/mterp/armv5te/bincmp.S b/vm/mterp/armv5te/bincmp.S
index 9b574a3..1f43918 100644
--- a/vm/mterp/armv5te/bincmp.S
+++ b/vm/mterp/armv5te/bincmp.S
@@ -19,7 +19,14 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
diff --git a/vm/mterp/armv5te/binop2addr.S b/vm/mterp/armv5te/binop2addr.S
index fc170a0..27afdda 100644
--- a/vm/mterp/armv5te/binop2addr.S
+++ b/vm/mterp/armv5te/binop2addr.S
@@ -17,8 +17,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if $chkzero
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
diff --git a/vm/mterp/armv5te/debug.c b/vm/mterp/armv5te/debug.c
index 301e27a..400bc95 100644
--- a/vm/mterp/armv5te/debug.c
+++ b/vm/mterp/armv5te/debug.c
@@ -13,17 +13,17 @@
register uint32_t rPC asm("r4");
register uint32_t rFP asm("r5");
register uint32_t rGLUE asm("r6");
- register uint32_t rIBASE asm("r7");
- register uint32_t rINST asm("r8");
+ register uint32_t rINST asm("r7");
+ register uint32_t rIBASE asm("r8");
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
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 rIBASE=%08x\n",
- rPC, rFP, rGLUE, rIBASE);
- printf(" : rINST=%08x r9=%08x r10=%08x\n", rINST, r9, r10);
+ 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;
@@ -63,12 +63,12 @@
* It is a direct (non-virtual) method if it is static, private,
* or a constructor.
*/
- bool isDirect =
+ bool isDirect =
((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
(method->name[0] == '<');
char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
-
+
printf("<%c:%s.%s %s> ",
isDirect ? 'D' : 'V',
method->clazz->descriptor,
diff --git a/vm/mterp/armv5te/entry.S b/vm/mterp/armv5te/entry.S
index 5b2cde0..f9e01a3 100644
--- a/vm/mterp/armv5te/entry.S
+++ b/vm/mterp/armv5te/entry.S
@@ -66,10 +66,21 @@
cmp r1, #kInterpEntryInstr @ usual case?
bne .Lnot_instr @ no, handle it
+#if defined(WITH_JIT)
+.Lno_singleStep:
+ /* Entry is always a possible trace start */
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
/* start executing the instruction at rPC */
FETCH_INST() @ load rINST from rPC
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
.Lnot_instr:
cmp r1, #kInterpEntryReturn @ were we returning from a method?
@@ -79,6 +90,22 @@
cmp r1, #kInterpEntryThrow @ were we throwing an exception?
beq common_exceptionThrown
+#if defined(WITH_JIT)
+.Lnot_throw:
+ ldr r0,[rGLUE, #offGlue_jitResume]
+ ldr r2,[rGLUE, #offGlue_jitResumePC]
+ cmp r1, #kInterpEntryResume @ resuming after Jit single-step?
+ bne .Lbad_arg
+ cmp rPC,r2
+ bne .Lno_singleStep @ must have branched, don't resume
+ mov r1, #kInterpEntryInstr
+ strb r1, [rGLUE, #offGlue_entryPoint]
+ ldr rINST, .LdvmCompilerTemplate
+ bx r0 @ re-enter the translation
+.LdvmCompilerTemplate:
+ .word dvmCompilerTemplateStart
+#endif
+
.Lbad_arg:
ldr r0, strBadEntryPoint
@ r1 holds value of entryPoint
diff --git a/vm/mterp/armv5te/footer.S b/vm/mterp/armv5te/footer.S
index 8f7cc41..004ee13 100644
--- a/vm/mterp/armv5te/footer.S
+++ b/vm/mterp/armv5te/footer.S
@@ -1,12 +1,188 @@
+
/*
* ===========================================================================
* Common subroutines and data
* ===========================================================================
*/
+
+
.text
.align 2
+#if defined(WITH_JIT)
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ mov rPC, r0
+#ifdef EXIT_STATS
+ mov r0,lr
+ bl dvmBumpPunt;
+#endif
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * r0 <= PC
+ * r1 <= PC of resume instruction
+ * lr <= resume point in translation
+ */
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ str lr,[rGLUE,#offGlue_jitResume]
+ str r1,[rGLUE,#offGlue_jitResumePC]
+ mov r1,#kInterpEntryInstr
+ @ enum is 4 byte in aapcs-EABI
+ str r1, [rGLUE, #offGlue_entryPoint]
+ mov rPC,r0
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ mov r2,#kJitSingleStep @ Ask for single step and then revert
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp to bail to debug interp
+ b common_gotoBail
+
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToTraceSelect
+dvmJitToTraceSelect:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq 2f
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/* No translation, so request one if profiling isn't disabled*/
+2:
+ adrl rIBASE, dvmAsmInstructionStart
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0, #0
+ bne common_selectTrace
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+#ifdef EXIT_STATS
+ bl dvmBumpNormal
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq toInterpreter @ go if not, otherwise do chain
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/*
+ * 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 EXIT_STATS
+ bl dvmBumpNoChain
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rGLUE & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+toInterpreter:
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ 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
+ * next instruction to execute, and rINST should be already loaded with
+ * the next opcode word, and r0 holds a pointer to the jit profile
+ * table (pJitProfTable).
+ */
+common_testUpdateProfile:
+ cmp r0,#0
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */
+
+common_updateProfile:
+ eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
+ GET_INST_OPCODE(ip)
+ subs r1,r1,#1 @ decrement counter
+ strb r1,[r0,r3,lsr #23] @ and store it
+ GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
+
+/*
+ * Here, we switch to the debug interpreter to request
+ * trace selection. First, though, check to see if there
+ * is already a native translation in place (and, if so,
+ * jump to it now).
+ */
+ mov r1,#255
+ strb r1,[r0,r3,lsr #23] @ reset counter
+ EXPORT_PC()
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
+ cmp r0,#0
+ beq common_selectTrace
+ bxne r0 @ jump to the translation
+common_selectTrace:
+ mov r2,#kJitTSelectRequest @ ask for trace selection
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp
+ b common_gotoBail
+
+#endif
+
/*
* Common code when a backward branch is taken.
*
@@ -16,9 +192,18 @@
common_backwardBranch:
mov r0, #kInterpEntryInstr
bl common_periodicChecks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/*
@@ -54,7 +239,7 @@
#endif
cmp r3, #0 @ suspend pending?
- bne 2f @ yes, check suspend
+ bne 2f @ yes, do full suspension check
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
@@ -72,6 +257,7 @@
2: @ check suspend
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ need for precise GC
b dvmCheckSuspendPending @ suspend if necessary, then return
3: @ debugger/profiler enabled, bail out
@@ -119,10 +305,12 @@
@ (very few methods have > 10 args; could unroll for common cases)
add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC]
sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
1: ldr r1, [r3], #4 @ val = *fp++
subs r2, r2, #1 @ count--
str r1, [r10], #4 @ *outs++ = val
bne 1b @ ...while count != 0
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
b .LinvokeArgsDone
/*
@@ -136,47 +324,50 @@
@ prepare to copy args to "outs" area of current frame
movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero
SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
- beq .LinvokeArgsDone @ if no args, skip the rest
- FETCH(r1, 2) @ r1<- GFED
+ FETCH(r1, 2) @ r1<- GFED (load here to hide latency)
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ beq .LinvokeArgsDone
- @ r0=methodToCall, r1=GFED, r2=count, r10=outs
+ @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
.LinvokeNonRange:
rsb r2, r2, #5 @ r2<- 5-r2
add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each
bl common_abort @ (skipped due to ARM prefetch)
5: and ip, rINST, #0x0f00 @ isolate A
- ldr r3, [rFP, ip, lsr #6] @ r3<- vA (shift right 8, left 2)
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2)
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vA
+ str r2, [r10, #-4]! @ *--outs = vA
4: and ip, r1, #0xf000 @ isolate G
- ldr r3, [rFP, ip, lsr #10] @ r3<- vG (shift right 12, left 2)
+ ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2)
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vG
+ str r2, [r10, #-4]! @ *--outs = vG
3: and ip, r1, #0x0f00 @ isolate F
- ldr r3, [rFP, ip, lsr #6] @ r3<- vF
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vF
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vF
+ str r2, [r10, #-4]! @ *--outs = vF
2: and ip, r1, #0x00f0 @ isolate E
- ldr r3, [rFP, ip, lsr #2] @ r3<- vE
+ ldr r2, [rFP, ip, lsr #2] @ r2<- vE
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vE
+ str r2, [r10, #-4]! @ *--outs = vE
1: and ip, r1, #0x000f @ isolate D
- ldr r3, [rFP, ip, lsl #2] @ r3<- vD
+ ldr r2, [rFP, ip, lsl #2] @ r2<- vD
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vD
+ str r2, [r10, #-4]! @ *--outs = vD
0: @ fall through to .LinvokeArgsDone
-.LinvokeArgsDone: @ r0=methodToCall
+.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
+ ldr r2, [r0, #offMethod_insns] @ r2<- method->insns
+ ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz
@ find space for the new stack frame, check for overflow
SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
- ldrh r2, [r0, #offMethod_registersSize] @ r2<- methodToCall->regsSize
- ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
- sub r1, r1, r2, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize)
SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea
@ bl common_dumpRegs
ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
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
@ set up newSaveArea
@@ -186,9 +377,11 @@
#endif
str rFP, [r10, #offStackSaveArea_prevFrame]
str rPC, [r10, #offStackSaveArea_savedPc]
+#if defined(WITH_JIT)
+ mov r9, #0
+ str r9, [r10, #offStackSaveArea_returnAddr]
+#endif
str r0, [r10, #offStackSaveArea_method]
-
- ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
tst r3, #ACC_NATIVE
bne .LinvokeNative
@@ -207,19 +400,31 @@
ldmfd sp!, {r0-r3}
*/
- @ Update "glue" values for the new method
- @ r0=methodToCall, r1=newFp
- ldr r3, [r0, #offMethod_clazz] @ r3<- method->clazz
- str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
- ldr r3, [r3, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
- ldr rPC, [r0, #offMethod_insns] @ rPC<- method->insns
- str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ ldrh r9, [r2] @ r9 <- load INST from new PC
+ ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ mov rPC, r2 @ publish new rPC
ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
- FETCH_INST() @ load rINST from rPC
+
+ @ Update "glue" values for the new method
+ @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
mov rFP, r1 @ fp = newFp
- GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ cmp r0,#0
+ bne common_updateProfile
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
.LinvokeNative:
@ Prep for the native call
@@ -312,22 +517,36 @@
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+ ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
@ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
cmp r2, #0 @ is this a break frame?
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
mov r1, #0 @ "want switch" = false
beq common_gotoBail @ break frame, bail out completely
- ldr rPC, [r0, #offStackSaveArea_savedPc] @ pc = saveArea->savedPc
- ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
- str r2, [rGLUE, #offGlue_method] @ glue->method = newSave->method
+ PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
- ldr r1, [r2, #offMethod_clazz] @ r1<- method->clazz
- FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
- ldr r1, [r1, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+#if defined(WITH_JIT)
+ ldr r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr
+ GET_JIT_PROF_TABLE(r0)
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r3, #0 @ caller is compiled code
+ blxne r3
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
+ mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/*
* Return handling, calls through "glue code".
@@ -350,12 +569,19 @@
*
* This does not return.
*/
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
common_exceptionThrown:
.LexceptionNew:
mov r0, #kInterpEntryThrow
mov r9, #0
bl common_periodicChecks
+#if defined(WITH_JIT)
+ mov r2,#kJitTSelectAbort @ abandon trace selection in progress
+ str r2,[rGLUE,#offGlue_jitState]
+#endif
+
ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self
ldr r9, [r10, #offThread_exception] @ r9<- self->exception
mov r1, r10 @ r1<- self
@@ -637,6 +863,38 @@
bx lr
.endif
+#if 0
+/*
+ * Experiment on VFP mode.
+ *
+ * uint32_t setFPSCR(uint32_t val, uint32_t mask)
+ *
+ * Updates the bits specified by "mask", setting them to the values in "val".
+ */
+setFPSCR:
+ and r0, r0, r1 @ make sure no stray bits are set
+ fmrx r2, fpscr @ get VFP reg
+ mvn r1, r1 @ bit-invert mask
+ and r2, r2, r1 @ clear masked bits
+ orr r2, r2, r0 @ set specified bits
+ fmxr fpscr, r2 @ set VFP reg
+ mov r0, r2 @ return new value
+ bx lr
+
+ .align 2
+ .global dvmConfigureFP
+ .type dvmConfigureFP, %function
+dvmConfigureFP:
+ stmfd sp!, {ip, lr}
+ /* 0x03000000 sets DN/FZ */
+ /* 0x00009f00 clears the six exception enable flags */
+ bl common_squeak0
+ mov r0, #0x03000000 @ r0<- 0x03000000
+ add r1, r0, #0x9f00 @ r1<- 0x03009f00
+ bl setFPSCR
+ ldmfd sp!, {ip, pc}
+#endif
+
/*
* String references, must be close to the code that uses them.
diff --git a/vm/mterp/armv5te/header.S b/vm/mterp/armv5te/header.S
index 6f9ba97..e129b15 100644
--- a/vm/mterp/armv5te/header.S
+++ b/vm/mterp/armv5te/header.S
@@ -33,7 +33,9 @@
r0 holds returns of <= 4 bytes
r0-r1 hold returns of 8 bytes, low word in r0
-Callee must save/restore r4+ (except r12) if it modifies them.
+Callee must save/restore r4+ (except r12) if it modifies them. If VFP
+is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
+s0-s15 (d0-d7, q0-a3) do not need to be.
Stack is "full descending". Only the arguments that don't fit in the first 4
registers are placed on the stack. "sp" points at the first stacked argument
@@ -54,8 +56,8 @@
r4 rPC interpreted program counter, used for fetching instructions
r5 rFP interpreted frame pointer, used for accessing locals and args
r6 rGLUE MterpGlue pointer
- r7 rIBASE interpreted instruction base pointer, used for computed goto
- r8 rINST first 16-bit code unit of current instruction
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
Macros are provided for common operations. Each macro MUST emit only
one instruction to make instruction-counting easier. They MUST NOT alter
@@ -66,8 +68,8 @@
#define rPC r4
#define rFP r5
#define rGLUE r6
-#define rIBASE r7
-#define rINST r8
+#define rINST r7
+#define rIBASE r8
/* save/restore the PC and/or FP from the glue struct */
#define LOAD_PC_FROM_GLUE() ldr rPC, [rGLUE, #offGlue_pc]
@@ -117,6 +119,13 @@
#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!
/*
+ * The operation performed here is similar to FETCH_ADVANCE_INST, except the
+ * src and dest registers are parameterized (not hard-wired to rPC and rINST).
+ */
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ ldrh _dreg, [_sreg, #(_count*2)]!
+
+/*
* Fetch the next instruction from an offset specified by _reg. Updates
* rPC to point to the next instruction. "_reg" must specify the distance
* in bytes, *not* 16-bit code units, and may be a signed value.
@@ -150,10 +159,17 @@
#define GET_INST_OPCODE(_reg) and _reg, rINST, #255
/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+#define GET_PREFETCHED_OPCODE(_oreg, _ireg) and _oreg, _ireg, #255
+
+/*
* Begin executing the opcode in _reg. Because this only jumps within the
* interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
*/
#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg, lsl #${handler_size_bits}
+#define GOTO_OPCODE_IFEQ(_reg) addeq pc, rIBASE, _reg, lsl #${handler_size_bits}
+#define GOTO_OPCODE_IFNE(_reg) addne pc, rIBASE, _reg, lsl #${handler_size_bits}
/*
* Get/set the 32-bit value from a Dalvik register.
@@ -161,6 +177,17 @@
#define GET_VREG(_reg, _vreg) ldr _reg, [rFP, _vreg, lsl #2]
#define SET_VREG(_reg, _vreg) str _reg, [rFP, _vreg, lsl #2]
+#if defined(WITH_JIT)
+#define GET_JIT_ENABLED(_reg) ldr _reg,[rGLUE,#offGlue_jitEnabled]
+#define GET_JIT_PROF_TABLE(_reg) ldr _reg,[rGLUE,#offGlue_pJitProfTable]
+#endif
+
+/*
+ * Convert a virtual register index into an address.
+ */
+#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
+ add _reg, rFP, _vreg, lsl #2
+
/*
* This is a #include, not a %include, because we want the C pre-processor
* to expand the macros into assembler assignment statements.
diff --git a/vm/mterp/armv5te/zcmp.S b/vm/mterp/armv5te/zcmp.S
index 7942632..861ca5b 100644
--- a/vm/mterp/armv5te/zcmp.S
+++ b/vm/mterp/armv5te/zcmp.S
@@ -16,7 +16,17 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
diff --git a/vm/mterp/armv6/OP_INT_TO_BYTE.S b/vm/mterp/armv6/OP_INT_TO_BYTE.S
new file mode 100644
index 0000000..40d8a5c
--- /dev/null
+++ b/vm/mterp/armv6/OP_INT_TO_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"sxtb r0, r0"}
diff --git a/vm/mterp/armv6/OP_INT_TO_CHAR.S b/vm/mterp/armv6/OP_INT_TO_CHAR.S
new file mode 100644
index 0000000..3f0fdad
--- /dev/null
+++ b/vm/mterp/armv6/OP_INT_TO_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"uxth r0, r0"}
diff --git a/vm/mterp/armv6/OP_INT_TO_SHORT.S b/vm/mterp/armv6/OP_INT_TO_SHORT.S
new file mode 100644
index 0000000..82274c4
--- /dev/null
+++ b/vm/mterp/armv6/OP_INT_TO_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv5te/unop.S" {"instr":"sxth r0, r0"}
diff --git a/vm/mterp/armv6t2/OP_ADD_DOUBLE_2ADDR.S b/vm/mterp/armv6t2/OP_ADD_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..d81ece9
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ADD_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"instr":"bl __aeabi_dadd"}
diff --git a/vm/mterp/armv6t2/OP_ADD_FLOAT_2ADDR.S b/vm/mterp/armv6t2/OP_ADD_FLOAT_2ADDR.S
new file mode 100644
index 0000000..ec6cdf1
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ADD_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"bl __aeabi_fadd"}
diff --git a/vm/mterp/armv6t2/OP_ADD_INT_2ADDR.S b/vm/mterp/armv6t2/OP_ADD_INT_2ADDR.S
new file mode 100644
index 0000000..af271cb
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ADD_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"add r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_ADD_INT_LIT16.S b/vm/mterp/armv6t2/OP_ADD_INT_LIT16.S
new file mode 100644
index 0000000..f66b1d4
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ADD_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopLit16.S" {"instr":"add r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_ADD_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_ADD_LONG_2ADDR.S
new file mode 100644
index 0000000..0e3a901
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ADD_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"preinstr":"adds r0, r0, r2", "instr":"adc r1, r1, r3"}
diff --git a/vm/mterp/armv6t2/OP_AND_INT_2ADDR.S b/vm/mterp/armv6t2/OP_AND_INT_2ADDR.S
new file mode 100644
index 0000000..e7b716d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_AND_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"and r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_AND_INT_LIT16.S b/vm/mterp/armv6t2/OP_AND_INT_LIT16.S
new file mode 100644
index 0000000..77bb06b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_AND_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopLit16.S" {"instr":"and r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_AND_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_AND_LONG_2ADDR.S
new file mode 100644
index 0000000..b77fbd2
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_AND_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"preinstr":"and r0, r0, r2", "instr":"and r1, r1, r3"}
diff --git a/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S b/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S
new file mode 100644
index 0000000..bb995e2
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_ARRAY_LENGTH.S
@@ -0,0 +1,15 @@
+%verify "executed"
+ /*
+ * Return the length of an array.
+ */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ GET_VREG(r0, r1) @ r0<- vB (object ref)
+ cmp r0, #0 @ is object null?
+ beq common_errNullObject @ yup, fail
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r3, [r0, #offArrayObject_length] @ r3<- array length
+ 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
new file mode 100644
index 0000000..0d6092c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_CONST_4.S
@@ -0,0 +1,10 @@
+%verify "executed"
+ /* const/4 vA, #+B */
+ mov r1, rINST, lsl #16 @ r1<- Bxxx0000
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r1, r1, asr #28 @ r1<- sssssssB (sign-extended)
+ 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_DIV_DOUBLE_2ADDR.S b/vm/mterp/armv6t2/OP_DIV_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..a3b7ffb
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DIV_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"instr":"bl __aeabi_ddiv"}
diff --git a/vm/mterp/armv6t2/OP_DIV_FLOAT_2ADDR.S b/vm/mterp/armv6t2/OP_DIV_FLOAT_2ADDR.S
new file mode 100644
index 0000000..125230c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DIV_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"bl __aeabi_fdiv"}
diff --git a/vm/mterp/armv6t2/OP_DIV_INT_2ADDR.S b/vm/mterp/armv6t2/OP_DIV_INT_2ADDR.S
new file mode 100644
index 0000000..8e58043
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DIV_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"bl __aeabi_idiv","chkzero":"1"}
diff --git a/vm/mterp/armv6t2/OP_DIV_INT_LIT16.S b/vm/mterp/armv6t2/OP_DIV_INT_LIT16.S
new file mode 100644
index 0000000..b4df053
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DIV_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopLit16.S" {"instr":"bl __aeabi_idiv","chkzero":"1"}
diff --git a/vm/mterp/armv6t2/OP_DIV_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_DIV_LONG_2ADDR.S
new file mode 100644
index 0000000..cbd9c2d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DIV_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"instr":"bl __aeabi_ldivmod", "chkzero":"1"}
diff --git a/vm/mterp/armv6t2/OP_DOUBLE_TO_FLOAT.S b/vm/mterp/armv6t2/OP_DOUBLE_TO_FLOAT.S
new file mode 100644
index 0000000..bdbb2fb
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopNarrower.S" {"instr":"bl __aeabi_d2f"}
diff --git a/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S b/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S
new file mode 100644
index 0000000..d3882f3
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_INT.S
@@ -0,0 +1,55 @@
+%verify "executed"
+/* EABI appears to have Java-style conversions of +inf/-inf/NaN */
+%include "armv6t2/unopNarrower.S" {"instr":"bl __aeabi_d2iz"}
+
+#if 0
+@include "armv5te/unopNarrower.S" {"instr":"bl d2i_doconv"}
+@break
+/*
+ * Convert the double in r0/r1 to an int in r0.
+ *
+ * We have to clip values to int min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+d2i_doconv:
+ stmfd sp!, {r4, r5, lr} @ save regs
+ mov r2, #0x80000000 @ maxint, as a double (low word)
+ mov r2, r2, asr #9 @ 0xffc00000
+ sub sp, sp, #4 @ align for EABI
+ mvn r3, #0xbe000000 @ maxint, as a double (high word)
+ sub r3, r3, #0x00200000 @ 0x41dfffff
+ mov r4, r0 @ save a copy of r0
+ mov r5, r1 @ and r1
+ bl __aeabi_dcmpge @ is arg >= maxint?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0x80000000 @ return maxint (0x7fffffff)
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r3, #0xc1000000 @ minint, as a double (high word)
+ add r3, r3, #0x00e00000 @ 0xc1e00000
+ mov r2, #0 @ minint, as a double (low word)
+ bl __aeabi_dcmple @ is arg <= minint?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0x80000000 @ return minint (80000000)
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r2, r4 @ compare against self
+ mov r3, r5
+ bl __aeabi_dcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ beq 1f @ return zero for NaN
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ bl __aeabi_d2iz @ convert double to int
+
+1:
+ 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
new file mode 100644
index 0000000..a9ecab7
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_DOUBLE_TO_LONG.S
@@ -0,0 +1,54 @@
+%verify "executed"
+@include "armv6t2/unopWide.S" {"instr":"bl __aeabi_d2lz"}
+%include "armv6t2/unopWide.S" {"instr":"bl d2l_doconv"}
+
+%break
+/*
+ * Convert the double in r0/r1 to a long in r0/r1.
+ *
+ * We have to clip values to long min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+d2l_doconv:
+ stmfd sp!, {r4, r5, lr} @ save regs
+ mov r3, #0x43000000 @ maxlong, as a double (high word)
+ add r3, #0x00e00000 @ 0x43e00000
+ mov r2, #0 @ maxlong, as a double (low word)
+ sub sp, sp, #4 @ align for EABI
+ mov r4, r0 @ save a copy of r0
+ mov r5, r1 @ and r1
+ bl __aeabi_dcmpge @ is arg >= maxlong?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0 @ return maxlong (7fffffffffffffff)
+ mvnne r1, #0x80000000
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r3, #0xc3000000 @ minlong, as a double (high word)
+ add r3, #0x00e00000 @ 0xc3e00000
+ mov r2, #0 @ minlong, as a double (low word)
+ bl __aeabi_dcmple @ is arg <= minlong?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0 @ return minlong (8000000000000000)
+ movne r1, #0x80000000
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r2, r4 @ compare against self
+ mov r3, r5
+ bl __aeabi_dcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ moveq r1, #0 @ return zero for NaN
+ beq 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ bl __aeabi_d2lz @ convert double to long
+
+1:
+ add sp, sp, #4
+ ldmfd sp!, {r4, r5, pc}
+
diff --git a/vm/mterp/armv6t2/OP_FLOAT_TO_DOUBLE.S b/vm/mterp/armv6t2/OP_FLOAT_TO_DOUBLE.S
new file mode 100644
index 0000000..64ca64c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWider.S" {"instr":"bl __aeabi_f2d"}
diff --git a/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S b/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S
new file mode 100644
index 0000000..444ebae
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_INT.S
@@ -0,0 +1,41 @@
+%verify "executed"
+/* EABI appears to have Java-style conversions of +inf/-inf/NaN */
+%include "armv6t2/unop.S" {"instr":"bl __aeabi_f2iz"}
+
+#if 0
+@include "armv6t2/unop.S" {"instr":"bl f2i_doconv"}
+@break
+/*
+ * Convert the float in r0 to an int in r0.
+ *
+ * We have to clip values to int min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+f2i_doconv:
+ stmfd sp!, {r4, lr}
+ mov r1, #0x4f000000 @ (float)maxint
+ mov r4, r0
+ bl __aeabi_fcmpge @ is arg >= maxint?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0x80000000 @ return maxint (7fffffff)
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, #0xcf000000 @ (float)minint
+ bl __aeabi_fcmple @ is arg <= minint?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0x80000000 @ return minint (80000000)
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, r4
+ bl __aeabi_fcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ ldmeqfd sp!, {r4, pc} @ return zero for NaN
+
+ mov r0, r4 @ recover arg
+ 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
new file mode 100644
index 0000000..5efd04b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_FLOAT_TO_LONG.S
@@ -0,0 +1,41 @@
+%verify "executed"
+@include "armv6t2/unopWider.S" {"instr":"bl __aeabi_f2lz"}
+%include "armv6t2/unopWider.S" {"instr":"bl f2l_doconv"}
+
+%break
+/*
+ * Convert the float in r0 to a long in r0/r1.
+ *
+ * We have to clip values to long min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+f2l_doconv:
+ stmfd sp!, {r4, lr}
+ mov r1, #0x5f000000 @ (float)maxlong
+ mov r4, r0
+ bl __aeabi_fcmpge @ is arg >= maxlong?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0 @ return maxlong (7fffffff)
+ mvnne r1, #0x80000000
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, #0xdf000000 @ (float)minlong
+ bl __aeabi_fcmple @ is arg <= minlong?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0 @ return minlong (80000000)
+ movne r1, #0x80000000
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, r4
+ bl __aeabi_fcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ moveq r1, #0 @ return zero for NaN
+ ldmeqfd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ bl __aeabi_f2lz @ convert float to long
+ ldmfd sp!, {r4, pc}
+
diff --git a/vm/mterp/armv6t2/OP_IF_EQ.S b/vm/mterp/armv6t2/OP_IF_EQ.S
new file mode 100644
index 0000000..d14b10b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IF_EQ.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/bincmp.S" { "revcmp":"ne" }
diff --git a/vm/mterp/armv6t2/OP_IF_GE.S b/vm/mterp/armv6t2/OP_IF_GE.S
new file mode 100644
index 0000000..e6c518d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IF_GE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/bincmp.S" { "revcmp":"lt" }
diff --git a/vm/mterp/armv6t2/OP_IF_GT.S b/vm/mterp/armv6t2/OP_IF_GT.S
new file mode 100644
index 0000000..6e89b3c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IF_GT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/bincmp.S" { "revcmp":"le" }
diff --git a/vm/mterp/armv6t2/OP_IF_LE.S b/vm/mterp/armv6t2/OP_IF_LE.S
new file mode 100644
index 0000000..0be9f60
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IF_LE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/bincmp.S" { "revcmp":"gt" }
diff --git a/vm/mterp/armv6t2/OP_IF_LT.S b/vm/mterp/armv6t2/OP_IF_LT.S
new file mode 100644
index 0000000..cea79b1
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IF_LT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/bincmp.S" { "revcmp":"ge" }
diff --git a/vm/mterp/armv6t2/OP_IF_NE.S b/vm/mterp/armv6t2/OP_IF_NE.S
new file mode 100644
index 0000000..ad1f936
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IF_NE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/bincmp.S" { "revcmp":"eq" }
diff --git a/vm/mterp/armv6t2/OP_IGET.S b/vm/mterp/armv6t2/OP_IGET.S
new file mode 100644
index 0000000..537c534
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET.S
@@ -0,0 +1,46 @@
+%default { "load":"ldr", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 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 .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
+ bne .L${opcode}_finish
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.L${opcode}_finish:
+ @bl common_squeak${sqnum}
+ cmp r9, #0 @ check object for null
+ 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)
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
new file mode 100644
index 0000000..83714d5
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+ /* For: iget-quick, iget-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ FETCH(r1, 1) @ r1<- 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
+ ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
new file mode 100644
index 0000000..948d53d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET_WIDE.S
@@ -0,0 +1,43 @@
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * 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 .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
+ bne .L${opcode}_finish
+ b common_exceptionThrown
+%break
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.L${opcode}_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ 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
+
diff --git a/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S b/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S
new file mode 100644
index 0000000..129f424
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IGET_WIDE_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+ /* iget-wide-quick vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ FETCH(r1, 1) @ r1<- 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)
+ 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
+
diff --git a/vm/mterp/armv6t2/OP_INT_TO_BYTE.S b/vm/mterp/armv6t2/OP_INT_TO_BYTE.S
new file mode 100644
index 0000000..27f92e6
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_INT_TO_BYTE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"sxtb r0, r0"}
diff --git a/vm/mterp/armv6t2/OP_INT_TO_CHAR.S b/vm/mterp/armv6t2/OP_INT_TO_CHAR.S
new file mode 100644
index 0000000..db1eaa3
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_INT_TO_CHAR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"uxth r0, r0"}
diff --git a/vm/mterp/armv6t2/OP_INT_TO_DOUBLE.S b/vm/mterp/armv6t2/OP_INT_TO_DOUBLE.S
new file mode 100644
index 0000000..38a2ef2
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_INT_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWider.S" {"instr":"bl __aeabi_i2d"}
diff --git a/vm/mterp/armv6t2/OP_INT_TO_FLOAT.S b/vm/mterp/armv6t2/OP_INT_TO_FLOAT.S
new file mode 100644
index 0000000..7407a73
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_INT_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"bl __aeabi_i2f"}
diff --git a/vm/mterp/armv6t2/OP_INT_TO_LONG.S b/vm/mterp/armv6t2/OP_INT_TO_LONG.S
new file mode 100644
index 0000000..e4d4221
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_INT_TO_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWider.S" {"instr":"mov r1, r0, asr #31"}
diff --git a/vm/mterp/armv6t2/OP_INT_TO_SHORT.S b/vm/mterp/armv6t2/OP_INT_TO_SHORT.S
new file mode 100644
index 0000000..6426a9f
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_INT_TO_SHORT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"sxth r0, r0"}
diff --git a/vm/mterp/armv6t2/OP_IPUT.S b/vm/mterp/armv6t2/OP_IPUT.S
new file mode 100644
index 0000000..10eea24
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT.S
@@ -0,0 +1,46 @@
+%default { "store":"str", "sqnum":"0" }
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /*
+ * General 32-bit instance field put.
+ *
+ * for: iput, iput-object, 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 .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}
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ ubfx r1, rINST, #8, #4 @ 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
+ $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
new file mode 100644
index 0000000..0b6d61c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+ /* For: iput-quick, iput-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ FETCH(r1, 1) @ r1<- field byte offset
+ GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ cmp r3, #0 @ check object for null
+ beq common_errNullObject @ object was null
+ GET_VREG(r0, r2) @ r0<- fp[A]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
new file mode 100644
index 0000000..5c1ab97
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT_WIDE.S
@@ -0,0 +1,40 @@
+%verify "executed"
+%verify "null object"
+%verify "field already resolved"
+%verify "field not yet resolved"
+%verify "field cannot be resolved"
+ /* 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 .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:
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ cmp r9, #0 @ check object for null
+ 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(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
new file mode 100644
index 0000000..5cf4798
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_IPUT_WIDE_QUICK.S
@@ -0,0 +1,16 @@
+%verify "executed"
+%verify "null object"
+ /* iput-wide-quick vA, vB, offset@CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r2, r1) @ r2<- fp[B], the object pointer
+ add r3, rFP, r0, lsl #2 @ r3<- &fp[A]
+ cmp r2, #0 @ check object for null
+ ldmia r3, {r0-r1} @ r0/r1<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH(r3, 1) @ r3<- field byte offset
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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_LONG_TO_DOUBLE.S b/vm/mterp/armv6t2/OP_LONG_TO_DOUBLE.S
new file mode 100644
index 0000000..f04f917
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_LONG_TO_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWide.S" {"instr":"bl __aeabi_l2d"}
diff --git a/vm/mterp/armv6t2/OP_LONG_TO_FLOAT.S b/vm/mterp/armv6t2/OP_LONG_TO_FLOAT.S
new file mode 100644
index 0000000..eaf983b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_LONG_TO_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopNarrower.S" {"instr":"bl __aeabi_l2f"}
diff --git a/vm/mterp/armv6t2/OP_MOVE.S b/vm/mterp/armv6t2/OP_MOVE.S
new file mode 100644
index 0000000..0c11d1a
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MOVE.S
@@ -0,0 +1,11 @@
+%verify "executed"
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ ubfx r0, rINST, #8, #4 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ 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
new file mode 100644
index 0000000..c896e62
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MOVE_WIDE.S
@@ -0,0 +1,13 @@
+%verify "executed"
+ /* move-wide vA, vB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[B]
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ 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_DOUBLE_2ADDR.S b/vm/mterp/armv6t2/OP_MUL_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..b2b1297
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MUL_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"instr":"bl __aeabi_dmul"}
diff --git a/vm/mterp/armv6t2/OP_MUL_FLOAT_2ADDR.S b/vm/mterp/armv6t2/OP_MUL_FLOAT_2ADDR.S
new file mode 100644
index 0000000..a48a3a0
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MUL_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"bl __aeabi_fmul"}
diff --git a/vm/mterp/armv6t2/OP_MUL_INT_2ADDR.S b/vm/mterp/armv6t2/OP_MUL_INT_2ADDR.S
new file mode 100644
index 0000000..e822fce
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MUL_INT_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+%include "armv6t2/binop2addr.S" {"instr":"mul r0, r1, r0"}
diff --git a/vm/mterp/armv6t2/OP_MUL_INT_LIT16.S b/vm/mterp/armv6t2/OP_MUL_INT_LIT16.S
new file mode 100644
index 0000000..a07e540
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MUL_INT_LIT16.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+%include "armv6t2/binopLit16.S" {"instr":"mul r0, r1, r0"}
diff --git a/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S
new file mode 100644
index 0000000..c050ecc
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_MUL_LONG_2ADDR.S
@@ -0,0 +1,26 @@
+%verify "executed"
+ /*
+ * Signed 64-bit integer multiply, "/2addr" version.
+ *
+ * See OP_MUL_LONG for an explanation.
+ *
+ * We get a little tight on registers, so to avoid looking up &fp[A]
+ * again we stuff it into rINST.
+ */
+ /* mul-long/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add rINST, rFP, r9, lsl #2 @ rINST<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia rINST, {r0-r1} @ r0/r1<- vAA/vAA+1
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ mov r0, rINST @ r0<- &fp[A] (free up rINST)
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ 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_NEG_DOUBLE.S b/vm/mterp/armv6t2/OP_NEG_DOUBLE.S
new file mode 100644
index 0000000..52ef346
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_NEG_DOUBLE.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWide.S" {"instr":"add r1, r1, #0x80000000"}
diff --git a/vm/mterp/armv6t2/OP_NEG_FLOAT.S b/vm/mterp/armv6t2/OP_NEG_FLOAT.S
new file mode 100644
index 0000000..34672d3
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_NEG_FLOAT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"add r0, r0, #0x80000000"}
diff --git a/vm/mterp/armv6t2/OP_NEG_INT.S b/vm/mterp/armv6t2/OP_NEG_INT.S
new file mode 100644
index 0000000..98fb1b3
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_NEG_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"rsb r0, r0, #0"}
diff --git a/vm/mterp/armv6t2/OP_NEG_LONG.S b/vm/mterp/armv6t2/OP_NEG_LONG.S
new file mode 100644
index 0000000..22f45fd
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_NEG_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWide.S" {"preinstr":"rsbs r0, r0, #0", "instr":"rsc r1, r1, #0"}
diff --git a/vm/mterp/armv6t2/OP_NOT_INT.S b/vm/mterp/armv6t2/OP_NOT_INT.S
new file mode 100644
index 0000000..5ce758e
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_NOT_INT.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unop.S" {"instr":"mvn r0, r0"}
diff --git a/vm/mterp/armv6t2/OP_NOT_LONG.S b/vm/mterp/armv6t2/OP_NOT_LONG.S
new file mode 100644
index 0000000..ac7e875
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_NOT_LONG.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/unopWide.S" {"preinstr":"mvn r0, r0", "instr":"mvn r1, r1"}
diff --git a/vm/mterp/armv6t2/OP_OR_INT_2ADDR.S b/vm/mterp/armv6t2/OP_OR_INT_2ADDR.S
new file mode 100644
index 0000000..b13b90c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_OR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"orr r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_OR_INT_LIT16.S b/vm/mterp/armv6t2/OP_OR_INT_LIT16.S
new file mode 100644
index 0000000..87db288
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_OR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopLit16.S" {"instr":"orr r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_OR_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_OR_LONG_2ADDR.S
new file mode 100644
index 0000000..a1891e5
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_OR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"preinstr":"orr r0, r0, r2", "instr":"orr r1, r1, r3"}
diff --git a/vm/mterp/armv6t2/OP_REM_DOUBLE_2ADDR.S b/vm/mterp/armv6t2/OP_REM_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..48e4cc3
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_REM_DOUBLE_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* EABI doesn't define a double remainder function, but libm does */
+%include "armv6t2/binopWide2addr.S" {"instr":"bl fmod"}
diff --git a/vm/mterp/armv6t2/OP_REM_FLOAT_2ADDR.S b/vm/mterp/armv6t2/OP_REM_FLOAT_2ADDR.S
new file mode 100644
index 0000000..8273df1
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_REM_FLOAT_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* EABI doesn't define a float remainder function, but libm does */
+%include "armv6t2/binop2addr.S" {"instr":"bl fmodf"}
diff --git a/vm/mterp/armv6t2/OP_REM_INT_2ADDR.S b/vm/mterp/armv6t2/OP_REM_INT_2ADDR.S
new file mode 100644
index 0000000..be4951d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_REM_INT_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* idivmod returns quotient in r0 and remainder in r1 */
+%include "armv6t2/binop2addr.S" {"instr":"bl __aeabi_idivmod", "result":"r1", "chkzero":"1"}
diff --git a/vm/mterp/armv6t2/OP_REM_INT_LIT16.S b/vm/mterp/armv6t2/OP_REM_INT_LIT16.S
new file mode 100644
index 0000000..ba66b48
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_REM_INT_LIT16.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* idivmod returns quotient in r0 and remainder in r1 */
+%include "armv6t2/binopLit16.S" {"instr":"bl __aeabi_idivmod", "result":"r1", "chkzero":"1"}
diff --git a/vm/mterp/armv6t2/OP_REM_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_REM_LONG_2ADDR.S
new file mode 100644
index 0000000..c663f78
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_REM_LONG_2ADDR.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+%include "armv6t2/binopWide2addr.S" {"instr":"bl __aeabi_ldivmod", "result0":"r2", "result1":"r3", "chkzero":"1"}
diff --git a/vm/mterp/armv6t2/OP_RSUB_INT.S b/vm/mterp/armv6t2/OP_RSUB_INT.S
new file mode 100644
index 0000000..761259c
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_RSUB_INT.S
@@ -0,0 +1,3 @@
+%verify "executed"
+/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
+%include "armv6t2/binopLit16.S" {"instr":"rsb r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_SHL_INT_2ADDR.S b/vm/mterp/armv6t2/OP_SHL_INT_2ADDR.S
new file mode 100644
index 0000000..c6959b2
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SHL_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"preinstr":"and r1, r1, #31", "instr":"mov r0, r0, asl r1"}
diff --git a/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S
new file mode 100644
index 0000000..bad569a
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SHL_LONG_2ADDR.S
@@ -0,0 +1,28 @@
+%verify "executed"
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shl-long/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ b .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+ 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_INT_2ADDR.S b/vm/mterp/armv6t2/OP_SHR_INT_2ADDR.S
new file mode 100644
index 0000000..ce0a2ce
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"preinstr":"and r1, r1, #31", "instr":"mov r0, r0, asr r1"}
diff --git a/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S
new file mode 100644
index 0000000..fa77b61
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SHR_LONG_2ADDR.S
@@ -0,0 +1,28 @@
+%verify "executed"
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shr-long/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
+ mov r1, r1, asr r2 @ r1<- r1 >> r2
+ b .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+ 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_SUB_DOUBLE_2ADDR.S b/vm/mterp/armv6t2/OP_SUB_DOUBLE_2ADDR.S
new file mode 100644
index 0000000..631187b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SUB_DOUBLE_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"instr":"bl __aeabi_dsub"}
diff --git a/vm/mterp/armv6t2/OP_SUB_FLOAT_2ADDR.S b/vm/mterp/armv6t2/OP_SUB_FLOAT_2ADDR.S
new file mode 100644
index 0000000..13ee1b4
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SUB_FLOAT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"bl __aeabi_fsub"}
diff --git a/vm/mterp/armv6t2/OP_SUB_INT_2ADDR.S b/vm/mterp/armv6t2/OP_SUB_INT_2ADDR.S
new file mode 100644
index 0000000..a3bd5e5
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SUB_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"sub r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_SUB_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_SUB_LONG_2ADDR.S
new file mode 100644
index 0000000..46dda45
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_SUB_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"preinstr":"subs r0, r0, r2", "instr":"sbc r1, r1, r3"}
diff --git a/vm/mterp/armv6t2/OP_USHR_INT_2ADDR.S b/vm/mterp/armv6t2/OP_USHR_INT_2ADDR.S
new file mode 100644
index 0000000..5d5808e
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_USHR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"preinstr":"and r1, r1, #31", "instr":"mov r0, r0, lsr r1"}
diff --git a/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S
new file mode 100644
index 0000000..1183d1f
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_USHR_LONG_2ADDR.S
@@ -0,0 +1,28 @@
+%verify "executed"
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* ushr-long/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
+ mov r1, r1, lsr r2 @ r1<- r1 >>> r2
+ b .L${opcode}_finish
+%break
+
+.L${opcode}_finish:
+ 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_XOR_INT_2ADDR.S b/vm/mterp/armv6t2/OP_XOR_INT_2ADDR.S
new file mode 100644
index 0000000..49c82d6
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_XOR_INT_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binop2addr.S" {"instr":"eor r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_XOR_INT_LIT16.S b/vm/mterp/armv6t2/OP_XOR_INT_LIT16.S
new file mode 100644
index 0000000..6fe178d
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_XOR_INT_LIT16.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopLit16.S" {"instr":"eor r0, r0, r1"}
diff --git a/vm/mterp/armv6t2/OP_XOR_LONG_2ADDR.S b/vm/mterp/armv6t2/OP_XOR_LONG_2ADDR.S
new file mode 100644
index 0000000..8d5ba2b
--- /dev/null
+++ b/vm/mterp/armv6t2/OP_XOR_LONG_2ADDR.S
@@ -0,0 +1,2 @@
+%verify "executed"
+%include "armv6t2/binopWide2addr.S" {"preinstr":"eor r0, r0, r2", "instr":"eor r1, r1, r3"}
diff --git a/vm/mterp/armv6t2/bincmp.S b/vm/mterp/armv6t2/bincmp.S
new file mode 100644
index 0000000..f3b81b0
--- /dev/null
+++ b/vm/mterp/armv6t2/bincmp.S
@@ -0,0 +1,31 @@
+%verify "branch taken"
+%verify "branch not taken"
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ b${revcmp} 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ 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
new file mode 100644
index 0000000..9b421bc
--- /dev/null
+++ b/vm/mterp/armv6t2/binop2addr.S
@@ -0,0 +1,33 @@
+%default {"preinstr":"", "result":"r0", "chkzero":"0"}
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if $chkzero
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ $preinstr @ optional op; may set condition codes
+ $instr @ $result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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
new file mode 100644
index 0000000..7bc9902
--- /dev/null
+++ b/vm/mterp/armv6t2/binopLit16.S
@@ -0,0 +1,30 @@
+%default {"result":"r0", "chkzero":"0"}
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if $chkzero
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ $instr @ $result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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
new file mode 100644
index 0000000..af83c7b
--- /dev/null
+++ b/vm/mterp/armv6t2/binopWide2addr.S
@@ -0,0 +1,35 @@
+%default {"preinstr":"", "result0":"r0", "result1":"r1", "chkzero":"0"}
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if $chkzero
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ $preinstr @ optional op; may set condition codes
+ $instr @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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/unop.S b/vm/mterp/armv6t2/unop.S
new file mode 100644
index 0000000..58465fe
--- /dev/null
+++ b/vm/mterp/armv6t2/unop.S
@@ -0,0 +1,20 @@
+%default {"preinstr":""}
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ $preinstr @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ $instr @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
diff --git a/vm/mterp/armv6t2/unopNarrower.S b/vm/mterp/armv6t2/unopNarrower.S
new file mode 100644
index 0000000..224e8e7
--- /dev/null
+++ b/vm/mterp/armv6t2/unopNarrower.S
@@ -0,0 +1,23 @@
+%default {"preinstr":""}
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0/r1", where
+ * "result" is a 32-bit quantity in r0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ *
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ ldmia r3, {r0-r1} @ r0/r1<- vB/vB+1
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ $preinstr @ optional op; may set condition codes
+ $instr @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
diff --git a/vm/mterp/armv6t2/unopWide.S b/vm/mterp/armv6t2/unopWide.S
new file mode 100644
index 0000000..62d8645
--- /dev/null
+++ b/vm/mterp/armv6t2/unopWide.S
@@ -0,0 +1,22 @@
+%default {"preinstr":""}
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ $preinstr @ optional op; may set condition codes
+ $instr @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
diff --git a/vm/mterp/armv6t2/unopWider.S b/vm/mterp/armv6t2/unopWider.S
new file mode 100644
index 0000000..7ec221b
--- /dev/null
+++ b/vm/mterp/armv6t2/unopWider.S
@@ -0,0 +1,20 @@
+%default {"preinstr":""}
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0", where
+ * "result" is a 64-bit quantity in r0/r1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ $preinstr @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ $instr @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
diff --git a/vm/mterp/c/OP_MONITOR_ENTER.c b/vm/mterp/c/OP_MONITOR_ENTER.c
index 4d70da7..c9d8999 100644
--- a/vm/mterp/c/OP_MONITOR_ENTER.c
+++ b/vm/mterp/c/OP_MONITOR_ENTER.c
@@ -9,9 +9,7 @@
if (!checkForNullExportPC(obj, fp, pc))
GOTO_exceptionThrown();
ILOGV("+ locking %p %s\n", obj, obj->clazz->descriptor);
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC(); /* need for stack trace */
-#endif
+ EXPORT_PC(); /* need for precise GC, also WITH_MONITOR_TRACKING */
dvmLockObject(self, obj);
#ifdef WITH_DEADLOCK_PREDICTION
if (dvmCheckException(self))
diff --git a/vm/mterp/c/OP_NEW_INSTANCE.c b/vm/mterp/c/OP_NEW_INSTANCE.c
index 8096579..ce04286 100644
--- a/vm/mterp/c/OP_NEW_INSTANCE.c
+++ b/vm/mterp/c/OP_NEW_INSTANCE.c
@@ -19,21 +19,13 @@
GOTO_exceptionThrown();
/*
- * Note: the verifier can ensure that this never happens, allowing us
- * to remove the check. However, the spec requires we throw the
- * exception at runtime, not verify time, so the verifier would
- * need to replace the new-instance call with a magic "throw
- * InstantiationError" instruction.
- *
- * Since this relies on the verifier, which is optional, we would
- * also need a "new-instance-quick" instruction to identify instances
- * that don't require the check.
+ * Verifier now tests for interface/abstract class.
*/
- if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
- dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
- clazz->descriptor);
- GOTO_exceptionThrown();
- }
+ //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+ // dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
+ // clazz->descriptor);
+ // GOTO_exceptionThrown();
+ //}
newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
if (newObj == NULL)
GOTO_exceptionThrown();
diff --git a/vm/mterp/c/OP_THROW_VERIFICATION_ERROR.c b/vm/mterp/c/OP_THROW_VERIFICATION_ERROR.c
new file mode 100644
index 0000000..85cc8fb
--- /dev/null
+++ b/vm/mterp/c/OP_THROW_VERIFICATION_ERROR.c
@@ -0,0 +1,7 @@
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR)
+ EXPORT_PC();
+ vsrc1 = INST_AA(inst);
+ ref = FETCH(1); /* class/field/method ref */
+ dvmThrowVerificationError(curMethod, vsrc1, ref);
+ GOTO_exceptionThrown();
+OP_END
diff --git a/vm/mterp/c/OP_UNUSED_ED.c b/vm/mterp/c/OP_UNUSED_ED.c
deleted file mode 100644
index c11348f..0000000
--- a/vm/mterp/c/OP_UNUSED_ED.c
+++ /dev/null
@@ -1,2 +0,0 @@
-HANDLE_OPCODE(OP_UNUSED_ED)
-OP_END
diff --git a/vm/mterp/c/gotoTargets.c b/vm/mterp/c/gotoTargets.c
index f52e3f0..37eaa20 100644
--- a/vm/mterp/c/gotoTargets.c
+++ b/vm/mterp/c/gotoTargets.c
@@ -836,6 +836,9 @@
#endif
newSaveArea->prevFrame = fp;
newSaveArea->savedPc = pc;
+#if defined(WITH_JIT)
+ newSaveArea->returnAddr = 0;
+#endif
newSaveArea->method = methodToCall;
if (!dvmIsNativeMethod(methodToCall)) {
@@ -929,4 +932,3 @@
}
assert(false); // should not get here
GOTO_TARGET_END
-
diff --git a/vm/mterp/c/header.c b/vm/mterp/c/header.c
index e35ded4..174c226 100644
--- a/vm/mterp/c/header.c
+++ b/vm/mterp/c/header.c
@@ -19,6 +19,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -46,7 +47,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -86,6 +87,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -109,9 +122,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -296,6 +313,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -309,29 +328,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -394,4 +405,3 @@
#endif
return true;
}
-
diff --git a/vm/mterp/common/FindInterface.h b/vm/mterp/common/FindInterface.h
new file mode 100644
index 0000000..021ed65
--- /dev/null
+++ b/vm/mterp/common/FindInterface.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+/* common includes */
+#include "Dalvik.h"
+
+/*
+ * Look up an interface on a class using the cache.
+ *
+ * This function used to be defined in mterp/c/header.c, but it is now used by
+ * the JIT compiler as well so it is separated into its own header file to
+ * avoid potential out-of-sync changes in the future.
+ */
+INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
+ u4 methodIdx, const Method* method, DvmDex* methodClassDex)
+{
+#define ATOMIC_CACHE_CALC \
+ dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
+
+ return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
+ DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
+
+#undef ATOMIC_CACHE_CALC
+}
diff --git a/vm/mterp/common/asm-constants.h b/vm/mterp/common/asm-constants.h
index 73292a9..5c37af6 100644
--- a/vm/mterp/common/asm-constants.h
+++ b/vm/mterp/common/asm-constants.h
@@ -101,14 +101,38 @@
MTERP_OFFSET(offGlue_pDebuggerActive, MterpGlue, pDebuggerActive, 40)
MTERP_OFFSET(offGlue_pActiveProfilers, MterpGlue, pActiveProfilers, 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_jitResume, MterpGlue, jitResume, 64)
+MTERP_OFFSET(offGlue_jitResumePC, MterpGlue, jitResumePC, 68)
+#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_jitResume, MterpGlue, jitResume, 60)
+MTERP_OFFSET(offGlue_jitResumePC, MterpGlue, jitResumePC, 64)
+#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_jitResume, MterpGlue, jitResume, 60)
+MTERP_OFFSET(offGlue_jitResumePC, MterpGlue, jitResumePC, 64)
+#endif
#else
MTERP_OFFSET(offGlue_entryPoint, MterpGlue, entryPoint, 40)
+#if defined(WITH_JIT)
+MTERP_OFFSET(offGlue_pJitProfTable, MterpGlue, pJitProfTable, 48)
+MTERP_OFFSET(offGlue_jitState, MterpGlue, jitState, 52)
+MTERP_OFFSET(offGlue_jitResume, MterpGlue, jitResume, 56)
+MTERP_OFFSET(offGlue_jitResumePC, MterpGlue, jitResumePC, 60)
+#endif
#endif
/* make sure all JValue union members are stored at the same offset */
MTERP_OFFSET(offGlue_retval_z, MterpGlue, retval.z, 8)
@@ -131,14 +155,16 @@
MTERP_OFFSET(offStackSaveArea_method, StackSaveArea, method, 12)
MTERP_OFFSET(offStackSaveArea_currentPc, StackSaveArea, xtra.currentPc, 16)
MTERP_OFFSET(offStackSaveArea_localRefTop, StackSaveArea, xtra.localRefTop, 16)
-MTERP_SIZEOF(sizeofStackSaveArea, StackSaveArea, 20)
+MTERP_OFFSET(offStackSaveArea_returnAddr, StackSaveArea, returnAddr, 20)
+MTERP_SIZEOF(sizeofStackSaveArea, StackSaveArea, 24)
#else
MTERP_OFFSET(offStackSaveArea_prevFrame, StackSaveArea, prevFrame, 0)
MTERP_OFFSET(offStackSaveArea_savedPc, StackSaveArea, savedPc, 4)
MTERP_OFFSET(offStackSaveArea_method, StackSaveArea, method, 8)
MTERP_OFFSET(offStackSaveArea_currentPc, StackSaveArea, xtra.currentPc, 12)
MTERP_OFFSET(offStackSaveArea_localRefTop, StackSaveArea, xtra.localRefTop, 12)
-MTERP_SIZEOF(sizeofStackSaveArea, StackSaveArea, 16)
+MTERP_OFFSET(offStackSaveArea_returnAddr, StackSaveArea, returnAddr, 16)
+MTERP_SIZEOF(sizeofStackSaveArea, StackSaveArea, 20)
#endif
/* InstField fields */
@@ -200,6 +226,20 @@
MTERP_CONSTANT(kInterpEntryInstr, 0)
MTERP_CONSTANT(kInterpEntryReturn, 1)
MTERP_CONSTANT(kInterpEntryThrow, 2)
+#if defined(WITH_JIT)
+MTERP_CONSTANT(kInterpEntryResume, 3)
+#endif
+
+#if defined(WITH_JIT)
+MTERP_CONSTANT(kJitOff, 0)
+MTERP_CONSTANT(kJitNormal, 1)
+MTERP_CONSTANT(kJitTSelectRequest, 2)
+MTERP_CONSTANT(kJitTSelect, 3)
+MTERP_CONSTANT(kJitTSelectAbort, 4)
+MTERP_CONSTANT(kJitTSelectEnd, 5)
+MTERP_CONSTANT(kJitSingleStep, 6)
+MTERP_CONSTANT(kJitSingleStepEnd, 7)
+#endif
/* ClassStatus enumeration */
MTERP_SIZEOF(sizeofClassStatus, ClassStatus, MTERP_SMALL_ENUM)
@@ -224,4 +264,3 @@
/* opcode number */
MTERP_CONSTANT(OP_MOVE_EXCEPTION, 0x0d)
-
diff --git a/vm/mterp/config-armv5te-vfp b/vm/mterp/config-armv5te-vfp
new file mode 100644
index 0000000..cc77002
--- /dev/null
+++ b/vm/mterp/config-armv5te-vfp
@@ -0,0 +1,105 @@
+# 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.
+
+#
+# Configuration for ARMv5TE targets with VFP support.
+#
+# This is just ARMv5TE with replacements for the handlers that can benefit
+# from floating-point instructions. Essentially all float/double
+# operations except for "remainder" and conversions to/from 64-bit ints.
+#
+
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# file header and basic definitions
+import c/header.c
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.c
+
+# highly-platform-specific defs
+import armv5te/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.c
+
+# arch-specific entry point to interpreter
+import armv5te/entry.S
+
+# opcode list; argument to op-start is default directory
+op-start armv5te
+ op OP_ADD_DOUBLE arm-vfp
+ op OP_ADD_DOUBLE_2ADDR arm-vfp
+ op OP_ADD_FLOAT arm-vfp
+ op OP_ADD_FLOAT_2ADDR arm-vfp
+ op OP_CMPG_DOUBLE arm-vfp
+ op OP_CMPG_FLOAT arm-vfp
+ op OP_CMPL_DOUBLE arm-vfp
+ op OP_CMPL_FLOAT arm-vfp
+ op OP_DIV_DOUBLE arm-vfp
+ op OP_DIV_DOUBLE_2ADDR arm-vfp
+ op OP_DIV_FLOAT arm-vfp
+ op OP_DIV_FLOAT_2ADDR arm-vfp
+ op OP_DOUBLE_TO_FLOAT arm-vfp
+ op OP_DOUBLE_TO_INT arm-vfp
+ op OP_FLOAT_TO_DOUBLE arm-vfp
+ op OP_FLOAT_TO_INT arm-vfp
+ op OP_INT_TO_DOUBLE arm-vfp
+ op OP_INT_TO_FLOAT arm-vfp
+ op OP_MUL_DOUBLE arm-vfp
+ op OP_MUL_DOUBLE_2ADDR arm-vfp
+ op OP_MUL_FLOAT arm-vfp
+ op OP_MUL_FLOAT_2ADDR arm-vfp
+ op OP_SUB_DOUBLE arm-vfp
+ op OP_SUB_DOUBLE_2ADDR arm-vfp
+ op OP_SUB_FLOAT arm-vfp
+ op OP_SUB_FLOAT_2ADDR arm-vfp
+
+ # use trivial integer operation
+ #op OP_NEG_DOUBLE armv5te
+ #op OP_NEG_FLOAT armv5te
+
+ # use __aeabi_* functions
+ #op OP_DOUBLE_TO_LONG armv5te
+ #op OP_FLOAT_TO_LONG armv5te
+ #op OP_LONG_TO_DOUBLE armv5te
+ #op OP_LONG_TO_FLOAT armv5te
+
+ # no "remainder" op in vfp or libgcc.a; use libc function
+ #op OP_REM_DOUBLE armv5te
+ #op OP_REM_DOUBLE_2ADDR armv5te
+ #op OP_REM_FLOAT armv5te
+ #op OP_REM_FLOAT_2ADDR armv5te
+
+ # experiment, unrelated to vfp
+ #op OP_INT_TO_BYTE armv6
+ #op OP_INT_TO_CHAR armv6
+ #op OP_INT_TO_SHORT armv6
+op-end
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+##import c/gotoTargets.c
+
+# end of defs; include this when cstubs/stubdefs.c is included
+import cstubs/enddefs.c
+
+# 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
new file mode 100644
index 0000000..9193632
--- /dev/null
+++ b/vm/mterp/config-armv7-a
@@ -0,0 +1,167 @@
+# 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.
+
+#
+# Configuration for ARMv7-A targets.
+#
+# This target includes Thumb-2 and Thumb2-EE support, as well as VFPLite.
+#
+# The difference in performance between this and ARMv5TE appears to be
+# negligible on a Cortex-A8 CPU, so this is really just an experiment.
+#
+
+handler-size 64
+
+# source for the instruction table stub
+asm-stub armv5te/stub.S
+
+# file header and basic definitions
+import c/header.c
+import armv5te/header.S
+
+# C pre-processor defines for stub C instructions
+import cstubs/stubdefs.c
+
+# highly-platform-specific defs
+import armv5te/platform.S
+
+# common defs for the C helpers; include this before the instruction handlers
+import c/opcommon.c
+
+# arch-specific entry point to interpreter
+import armv5te/entry.S
+
+# opcode list; argument to op-start is default directory
+op-start armv5te
+ # handlers that take advantage of >= ARMv6T2 instructions
+ op OP_ADD_DOUBLE_2ADDR armv6t2
+ op OP_ADD_FLOAT_2ADDR armv6t2
+ op OP_ADD_INT_2ADDR armv6t2
+ op OP_ADD_INT_LIT16 armv6t2
+ op OP_ADD_LONG_2ADDR armv6t2
+ op OP_AND_INT_2ADDR armv6t2
+ op OP_AND_INT_LIT16 armv6t2
+ op OP_AND_LONG_2ADDR armv6t2
+ op OP_ARRAY_LENGTH armv6t2
+ op OP_CONST_4 armv6t2
+ op OP_DIV_DOUBLE_2ADDR armv6t2
+ op OP_DIV_FLOAT_2ADDR armv6t2
+ op OP_DIV_INT_2ADDR armv6t2
+ op OP_DIV_INT_LIT16 armv6t2
+ op OP_DIV_LONG_2ADDR armv6t2
+ op OP_DOUBLE_TO_FLOAT armv6t2
+ op OP_DOUBLE_TO_INT armv6t2
+ op OP_DOUBLE_TO_LONG armv6t2
+ op OP_FLOAT_TO_DOUBLE armv6t2
+ op OP_FLOAT_TO_INT armv6t2
+ op OP_FLOAT_TO_LONG armv6t2
+ op OP_IF_EQ armv6t2
+ op OP_IF_GE armv6t2
+ op OP_IF_GT armv6t2
+ op OP_IF_LE armv6t2
+ op OP_IF_LT armv6t2
+ op OP_IF_NE armv6t2
+ op OP_IGET armv6t2
+ op OP_IGET_QUICK armv6t2
+ op OP_IGET_WIDE armv6t2
+ op OP_IGET_WIDE_QUICK armv6t2
+ op OP_INT_TO_BYTE armv6t2
+ op OP_INT_TO_CHAR armv6t2
+ op OP_INT_TO_DOUBLE armv6t2
+ op OP_INT_TO_FLOAT armv6t2
+ op OP_INT_TO_LONG armv6t2
+ op OP_INT_TO_SHORT armv6t2
+ op OP_IPUT armv6t2
+ op OP_IPUT_QUICK armv6t2
+ op OP_IPUT_WIDE armv6t2
+ op OP_IPUT_WIDE_QUICK armv6t2
+ op OP_LONG_TO_DOUBLE armv6t2
+ op OP_LONG_TO_FLOAT armv6t2
+ op OP_MOVE armv6t2
+ op OP_MOVE_WIDE armv6t2
+ op OP_MUL_DOUBLE_2ADDR armv6t2
+ op OP_MUL_FLOAT_2ADDR armv6t2
+ op OP_MUL_INT_2ADDR armv6t2
+ op OP_MUL_INT_LIT16 armv6t2
+ op OP_MUL_LONG_2ADDR armv6t2
+ op OP_NEG_DOUBLE armv6t2
+ op OP_NEG_FLOAT armv6t2
+ op OP_NEG_INT armv6t2
+ op OP_NEG_LONG armv6t2
+ op OP_NOT_INT armv6t2
+ op OP_NOT_LONG armv6t2
+ op OP_OR_INT_2ADDR armv6t2
+ op OP_OR_INT_LIT16 armv6t2
+ op OP_OR_LONG_2ADDR armv6t2
+ op OP_REM_DOUBLE_2ADDR armv6t2
+ op OP_REM_FLOAT_2ADDR armv6t2
+ op OP_REM_INT_2ADDR armv6t2
+ op OP_REM_INT_LIT16 armv6t2
+ op OP_REM_LONG_2ADDR armv6t2
+ op OP_RSUB_INT armv6t2
+ op OP_SHL_INT_2ADDR armv6t2
+ op OP_SHL_LONG_2ADDR armv6t2
+ op OP_SHR_INT_2ADDR armv6t2
+ op OP_SHR_LONG_2ADDR armv6t2
+ op OP_SUB_DOUBLE_2ADDR armv6t2
+ op OP_SUB_FLOAT_2ADDR armv6t2
+ op OP_SUB_INT_2ADDR armv6t2
+ op OP_SUB_LONG_2ADDR armv6t2
+ op OP_USHR_INT_2ADDR armv6t2
+ op OP_USHR_LONG_2ADDR armv6t2
+ op OP_XOR_INT_2ADDR armv6t2
+ op OP_XOR_INT_LIT16 armv6t2
+ op OP_XOR_LONG_2ADDR armv6t2
+
+ # floating point handlers that use VFP
+ # these override the handlers specified earlier
+ op OP_ADD_DOUBLE arm-vfp
+ op OP_ADD_DOUBLE_2ADDR arm-vfp
+ op OP_ADD_FLOAT arm-vfp
+ op OP_ADD_FLOAT_2ADDR arm-vfp
+ op OP_CMPG_DOUBLE arm-vfp
+ op OP_CMPG_FLOAT arm-vfp
+ op OP_CMPL_DOUBLE arm-vfp
+ op OP_CMPL_FLOAT arm-vfp
+ op OP_DIV_DOUBLE arm-vfp
+ op OP_DIV_DOUBLE_2ADDR arm-vfp
+ op OP_DIV_FLOAT arm-vfp
+ op OP_DIV_FLOAT_2ADDR arm-vfp
+ op OP_DOUBLE_TO_FLOAT arm-vfp
+ op OP_DOUBLE_TO_INT arm-vfp
+ op OP_FLOAT_TO_DOUBLE arm-vfp
+ op OP_FLOAT_TO_INT arm-vfp
+ op OP_INT_TO_DOUBLE arm-vfp
+ op OP_INT_TO_FLOAT arm-vfp
+ op OP_MUL_DOUBLE arm-vfp
+ op OP_MUL_DOUBLE_2ADDR arm-vfp
+ op OP_MUL_FLOAT arm-vfp
+ op OP_MUL_FLOAT_2ADDR arm-vfp
+ op OP_SUB_DOUBLE arm-vfp
+ op OP_SUB_DOUBLE_2ADDR arm-vfp
+ op OP_SUB_FLOAT arm-vfp
+ op OP_SUB_FLOAT_2ADDR arm-vfp
+op-end
+
+# "helper" code for C; include if you use any of the C stubs (this generates
+# object code, so it's normally excluded)
+##import c/gotoTargets.c
+
+# end of defs; include this when cstubs/stubdefs.c is included
+import cstubs/enddefs.c
+
+# common subroutines for asm
+import armv5te/footer.S
+import armv5te/debug.c
+
diff --git a/vm/mterp/config-x86 b/vm/mterp/config-x86
index b7139ca..d315a1c 100644
--- a/vm/mterp/config-x86
+++ b/vm/mterp/config-x86
@@ -33,6 +33,7 @@
# opcode list; argument to op-start is default directory
op-start x86
+ op OP_THROW_VERIFICATION_ERROR c
op-end
# arch-specific entry point to interpreter
diff --git a/vm/mterp/cstubs/stubdefs.c b/vm/mterp/cstubs/stubdefs.c
index 1de6f0e..d4162c8 100644
--- a/vm/mterp/cstubs/stubdefs.c
+++ b/vm/mterp/cstubs/stubdefs.c
@@ -107,7 +107,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
glue->entryPoint = _entryPoint; \
diff --git a/vm/mterp/gen-mterp.py b/vm/mterp/gen-mterp.py
index e342266..e685350 100755
--- a/vm/mterp/gen-mterp.py
+++ b/vm/mterp/gen-mterp.py
@@ -24,6 +24,7 @@
interp_defs_file = "../../libdex/OpCode.h" # need opcode list
+verbose = False
handler_size_bits = -1000
handler_size_bytes = -1000
in_op_start = 0 # 0=not started, 1=started, 2=ended
@@ -129,6 +130,9 @@
index = opcodes.index(tokens[1])
except ValueError:
raise DataParseError("unknown opcode %s" % tokens[1])
+ if opcode_locations.has_key(tokens[1]):
+ print "Warning: op overrides earlier %s (%s -> %s)" \
+ % (tokens[1], opcode_locations[tokens[1]], tokens[2])
opcode_locations[tokens[1]] = tokens[2]
#
@@ -228,7 +232,8 @@
def loadAndEmitC(location, opindex):
op = opcodes[opindex]
source = "%s/%s.c" % (location, op)
- print " emit %s --> C" % source
+ if verbose:
+ print " emit %s --> C" % source
dict = getGlobalSubDict()
dict.update({ "opcode":op, "opnum":opindex })
@@ -245,7 +250,8 @@
source = "%s/%s.S" % (location, op)
dict = getGlobalSubDict()
dict.update({ "opcode":op, "opnum":opindex })
- print " emit %s --> asm" % source
+ if verbose:
+ print " emit %s --> asm" % source
emitAsmHeader(asm_fp, dict)
appendSourceFile(source, dict, asm_fp, sister_list)
diff --git a/vm/mterp/out/InterpAsm-armv4t.S b/vm/mterp/out/InterpAsm-armv4t.S
index d60571b..b0aa69b 100644
--- a/vm/mterp/out/InterpAsm-armv4t.S
+++ b/vm/mterp/out/InterpAsm-armv4t.S
@@ -40,7 +40,9 @@
r0 holds returns of <= 4 bytes
r0-r1 hold returns of 8 bytes, low word in r0
-Callee must save/restore r4+ (except r12) if it modifies them.
+Callee must save/restore r4+ (except r12) if it modifies them. If VFP
+is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
+s0-s15 (d0-d7, q0-a3) do not need to be.
Stack is "full descending". Only the arguments that don't fit in the first 4
registers are placed on the stack. "sp" points at the first stacked argument
@@ -61,8 +63,8 @@
r4 rPC interpreted program counter, used for fetching instructions
r5 rFP interpreted frame pointer, used for accessing locals and args
r6 rGLUE MterpGlue pointer
- r7 rIBASE interpreted instruction base pointer, used for computed goto
- r8 rINST first 16-bit code unit of current instruction
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
Macros are provided for common operations. Each macro MUST emit only
one instruction to make instruction-counting easier. They MUST NOT alter
@@ -73,8 +75,8 @@
#define rPC r4
#define rFP r5
#define rGLUE r6
-#define rIBASE r7
-#define rINST r8
+#define rINST r7
+#define rIBASE r8
/* save/restore the PC and/or FP from the glue struct */
#define LOAD_PC_FROM_GLUE() ldr rPC, [rGLUE, #offGlue_pc]
@@ -124,6 +126,13 @@
#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!
/*
+ * The operation performed here is similar to FETCH_ADVANCE_INST, except the
+ * src and dest registers are parameterized (not hard-wired to rPC and rINST).
+ */
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ ldrh _dreg, [_sreg, #(_count*2)]!
+
+/*
* Fetch the next instruction from an offset specified by _reg. Updates
* rPC to point to the next instruction. "_reg" must specify the distance
* in bytes, *not* 16-bit code units, and may be a signed value.
@@ -157,10 +166,17 @@
#define GET_INST_OPCODE(_reg) and _reg, rINST, #255
/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+#define GET_PREFETCHED_OPCODE(_oreg, _ireg) and _oreg, _ireg, #255
+
+/*
* Begin executing the opcode in _reg. Because this only jumps within the
* interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
*/
#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFEQ(_reg) addeq pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFNE(_reg) addne pc, rIBASE, _reg, lsl #6
/*
* Get/set the 32-bit value from a Dalvik register.
@@ -168,6 +184,17 @@
#define GET_VREG(_reg, _vreg) ldr _reg, [rFP, _vreg, lsl #2]
#define SET_VREG(_reg, _vreg) str _reg, [rFP, _vreg, lsl #2]
+#if defined(WITH_JIT)
+#define GET_JIT_ENABLED(_reg) ldr _reg,[rGLUE,#offGlue_jitEnabled]
+#define GET_JIT_PROF_TABLE(_reg) ldr _reg,[rGLUE,#offGlue_pJitProfTable]
+#endif
+
+/*
+ * Convert a virtual register index into an address.
+ */
+#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
+ add _reg, rFP, _vreg, lsl #2
+
/*
* This is a #include, not a %include, because we want the C pre-processor
* to expand the macros into assembler assignment statements.
@@ -282,10 +309,21 @@
cmp r1, #kInterpEntryInstr @ usual case?
bne .Lnot_instr @ no, handle it
+#if defined(WITH_JIT)
+.Lno_singleStep:
+ /* Entry is always a possible trace start */
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
/* start executing the instruction at rPC */
FETCH_INST() @ load rINST from rPC
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
.Lnot_instr:
cmp r1, #kInterpEntryReturn @ were we returning from a method?
@@ -295,6 +333,22 @@
cmp r1, #kInterpEntryThrow @ were we throwing an exception?
beq common_exceptionThrown
+#if defined(WITH_JIT)
+.Lnot_throw:
+ ldr r0,[rGLUE, #offGlue_jitResume]
+ ldr r2,[rGLUE, #offGlue_jitResumePC]
+ cmp r1, #kInterpEntryResume @ resuming after Jit single-step?
+ bne .Lbad_arg
+ cmp rPC,r2
+ bne .Lno_singleStep @ must have branched, don't resume
+ mov r1, #kInterpEntryInstr
+ strb r1, [rGLUE, #offGlue_entryPoint]
+ ldr rINST, .LdvmCompilerTemplate
+ bx r0 @ re-enter the translation
+.LdvmCompilerTemplate:
+ .word dvmCompilerTemplateStart
+#endif
+
.Lbad_arg:
ldr r0, strBadEntryPoint
@ r1 holds value of entryPoint
@@ -450,7 +504,7 @@
add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
add r2, rFP, r2, lsl #2 @ r2<- &fp[AAAA]
ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
@@ -818,9 +872,7 @@
GET_VREG(r1, r2) @ r1<- vAA (object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
cmp r1, #0 @ null object?
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC() @ export PC so we can grab stack trace
-#endif
+ EXPORT_PC() @ need for precise GC, MONITOR_TRACKING
beq common_errNullObject @ null object, throw an exception
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
bl dvmLockObject @ call(self, obj)
@@ -956,11 +1008,9 @@
cmp r1, #CLASS_INITIALIZED @ has class been initialized?
bne .LOP_NEW_INSTANCE_needinit @ no, init class now
.LOP_NEW_INSTANCE_initialized: @ r0=class
- ldr r3, [r0, #offClassObject_accessFlags] @ r3<- clazz->accessFlags
- tst r3, #(ACC_INTERFACE|ACC_ABSTRACT) @ abstract or interface?
mov r1, #ALLOC_DONT_TRACK @ flags for alloc call
- beq .LOP_NEW_INSTANCE_finish @ concrete class, continue
- b .LOP_NEW_INSTANCE_abstract @ fail
+ bl dvmAllocObject @ r0<- new object
+ b .LOP_NEW_INSTANCE_finish @ continue
/* ------------------------------ */
.balign 64
@@ -1095,10 +1145,18 @@
movs r9, r0, asr #24 @ r9<- ssssssAA (sign-extended)
mov r9, r9, lsl #1 @ r9<- byte offset
bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
+#endif
/* ------------------------------ */
.balign 64
@@ -1114,9 +1172,18 @@
FETCH_S(r0, 1) @ r0<- ssssAAAA (sign-extended)
movs r9, r0, asl #1 @ r9<- byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/* ------------------------------ */
@@ -1141,10 +1208,18 @@
orrs r0, r0, r1, lsl #16 @ r0<- AAAAaaaa, check sign
mov r9, r0, asl #1 @ r9<- byte offset
ble common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
+#endif
/* ------------------------------ */
.balign 64
@@ -1170,9 +1245,18 @@
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/* ------------------------------ */
@@ -1200,9 +1284,18 @@
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1449,9 +1542,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1479,9 +1579,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1509,9 +1616,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1539,9 +1653,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1569,9 +1690,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1599,9 +1727,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1626,9 +1761,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1653,9 +1798,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1680,9 +1835,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1707,9 +1872,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1734,9 +1909,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1761,9 +1946,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -3826,20 +4021,23 @@
*/
d2i_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
- ldr r2, .LOP_DOUBLE_TO_INT_maxlo @ (double)maxint, lo
- ldr r3, .LOP_DOUBLE_TO_INT_maxhi @ (double)maxint, hi
+ mov r2, #0x80000000 @ maxint, as a double (low word)
+ mov r2, r2, asr #9 @ 0xffc00000
sub sp, sp, #4 @ align for EABI
- mov r4, r0 @ save r0
+ mvn r3, #0xbe000000 @ maxint, as a double (high word)
+ sub r3, r3, #0x00200000 @ 0x41dfffff
+ mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxint?
cmp r0, #0 @ nonzero == yes
- mvnne r0, #0x80000000 @ return maxint (7fffffff)
+ mvnne r0, #0x80000000 @ return maxint (0x7fffffff)
bne 1f
mov r0, r4 @ recover arg
mov r1, r5
- ldr r3, .LOP_DOUBLE_TO_INT_min @ (double)minint, hi
- mov r2, #0 @ (double)minint, lo
+ mov r3, #0xc1000000 @ minint, as a double (high word)
+ add r3, r3, #0x00e00000 @ 0xc1e00000
+ mov r2, #0 @ minint, as a double (low word)
bl __aeabi_dcmple @ is arg <= minint?
cmp r0, #0 @ nonzero == yes
movne r0, #0x80000000 @ return minint (80000000)
@@ -3860,13 +4058,6 @@
1:
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
-.LOP_DOUBLE_TO_INT_maxlo:
- .word 0xffc00000 @ maxint, as a double (low word)
-.LOP_DOUBLE_TO_INT_maxhi:
- .word 0x41dfffff @ maxint, as a double (high word)
-.LOP_DOUBLE_TO_INT_min:
- .word 0xc1e00000 @ minint, as a double (high word)
#endif
@@ -5378,8 +5569,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5418,8 +5609,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5459,8 +5650,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5499,8 +5690,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5540,8 +5731,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5580,8 +5771,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5620,8 +5811,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5660,8 +5851,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5700,8 +5891,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5740,8 +5931,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5780,8 +5971,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6224,8 +6415,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6264,8 +6455,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6304,8 +6495,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6344,8 +6535,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6385,8 +6576,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -7435,11 +7626,20 @@
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_ED: /* 0xed */
-/* File: armv5te/OP_UNUSED_ED.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR.S */
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ FETCH(r2, 1) @ r2<- BBBB
+ EXPORT_PC() @ export the PC
+ mov r1, rINST, lsr #8 @ r1<- AA
+ bl dvmThrowVerificationError @ always throws
+ b common_exceptionThrown @ handle exception
/* ------------------------------ */
@@ -7953,8 +8153,7 @@
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
-.LOP_NEW_INSTANCE_finish: @ r0=class
- bl dvmAllocObject @ r0<- new object
+.LOP_NEW_INSTANCE_finish: @ r0=new object
mov r3, rINST, lsr #8 @ r3<- AA
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle the exception
@@ -7990,18 +8189,6 @@
bne .LOP_NEW_INSTANCE_resolved @ no, continue
b common_exceptionThrown @ yes, handle exception
- /*
- * We can't instantiate an abstract class or interface, so throw an
- * InstantiationError with the class descriptor as the message.
- *
- * r0 holds class object
- */
-.LOP_NEW_INSTANCE_abstract:
- ldr r1, [r0, #offClassObject_descriptor]
- ldr r0, .LstrInstantiationErrorPtr
- bl dvmThrowExceptionWithClassMessage
- b common_exceptionThrown
-
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
@@ -9142,10 +9329,11 @@
*/
d2l_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
- ldr r3, .LOP_DOUBLE_TO_LONG_max @ (double)maxlong, hi
+ mov r3, #0x43000000 @ maxlong, as a double (high word)
+ add r3, #0x00e00000 @ 0x43e00000
+ mov r2, #0 @ maxlong, as a double (low word)
sub sp, sp, #4 @ align for EABI
- mov r2, #0 @ (double)maxlong, lo
- mov r4, r0 @ save r0
+ mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxlong?
cmp r0, #0 @ nonzero == yes
@@ -9155,8 +9343,9 @@
mov r0, r4 @ recover arg
mov r1, r5
- ldr r3, .LOP_DOUBLE_TO_LONG_min @ (double)minlong, hi
- mov r2, #0 @ (double)minlong, lo
+ mov r3, #0xc3000000 @ minlong, as a double (high word)
+ add r3, #0x00e00000 @ 0xc3e00000
+ mov r2, #0 @ minlong, as a double (low word)
bl __aeabi_dcmple @ is arg <= minlong?
cmp r0, #0 @ nonzero == yes
movne r0, #0 @ return minlong (8000000000000000)
@@ -9180,11 +9369,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-.LOP_DOUBLE_TO_LONG_max:
- .word 0x43e00000 @ maxlong, as a double (high word)
-.LOP_DOUBLE_TO_LONG_min:
- .word 0xc3e00000 @ minlong, as a double (high word)
-
/* continuation for OP_MUL_LONG */
@@ -9286,15 +9470,191 @@
dvmAsmSisterEnd:
/* File: armv5te/footer.S */
+
/*
* ===========================================================================
* Common subroutines and data
* ===========================================================================
*/
+
+
.text
.align 2
+#if defined(WITH_JIT)
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ mov rPC, r0
+#ifdef EXIT_STATS
+ mov r0,lr
+ bl dvmBumpPunt;
+#endif
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * r0 <= PC
+ * r1 <= PC of resume instruction
+ * lr <= resume point in translation
+ */
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ str lr,[rGLUE,#offGlue_jitResume]
+ str r1,[rGLUE,#offGlue_jitResumePC]
+ mov r1,#kInterpEntryInstr
+ @ enum is 4 byte in aapcs-EABI
+ str r1, [rGLUE, #offGlue_entryPoint]
+ mov rPC,r0
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ mov r2,#kJitSingleStep @ Ask for single step and then revert
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp to bail to debug interp
+ b common_gotoBail
+
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToTraceSelect
+dvmJitToTraceSelect:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq 2f
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/* No translation, so request one if profiling isn't disabled*/
+2:
+ adrl rIBASE, dvmAsmInstructionStart
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0, #0
+ bne common_selectTrace
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+#ifdef EXIT_STATS
+ bl dvmBumpNormal
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq toInterpreter @ go if not, otherwise do chain
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/*
+ * 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 EXIT_STATS
+ bl dvmBumpNoChain
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rGLUE & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+toInterpreter:
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ 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
+ * next instruction to execute, and rINST should be already loaded with
+ * the next opcode word, and r0 holds a pointer to the jit profile
+ * table (pJitProfTable).
+ */
+common_testUpdateProfile:
+ cmp r0,#0
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */
+
+common_updateProfile:
+ eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
+ GET_INST_OPCODE(ip)
+ subs r1,r1,#1 @ decrement counter
+ strb r1,[r0,r3,lsr #23] @ and store it
+ GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
+
+/*
+ * Here, we switch to the debug interpreter to request
+ * trace selection. First, though, check to see if there
+ * is already a native translation in place (and, if so,
+ * jump to it now).
+ */
+ mov r1,#255
+ strb r1,[r0,r3,lsr #23] @ reset counter
+ EXPORT_PC()
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
+ cmp r0,#0
+ beq common_selectTrace
+ bxne r0 @ jump to the translation
+common_selectTrace:
+ mov r2,#kJitTSelectRequest @ ask for trace selection
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp
+ b common_gotoBail
+
+#endif
+
/*
* Common code when a backward branch is taken.
*
@@ -9304,9 +9664,18 @@
common_backwardBranch:
mov r0, #kInterpEntryInstr
bl common_periodicChecks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/*
@@ -9342,7 +9711,7 @@
#endif
cmp r3, #0 @ suspend pending?
- bne 2f @ yes, check suspend
+ bne 2f @ yes, do full suspension check
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
@@ -9360,6 +9729,7 @@
2: @ check suspend
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ need for precise GC
b dvmCheckSuspendPending @ suspend if necessary, then return
3: @ debugger/profiler enabled, bail out
@@ -9407,10 +9777,12 @@
@ (very few methods have > 10 args; could unroll for common cases)
add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC]
sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
1: ldr r1, [r3], #4 @ val = *fp++
subs r2, r2, #1 @ count--
str r1, [r10], #4 @ *outs++ = val
bne 1b @ ...while count != 0
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
b .LinvokeArgsDone
/*
@@ -9424,47 +9796,50 @@
@ prepare to copy args to "outs" area of current frame
movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero
SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
- beq .LinvokeArgsDone @ if no args, skip the rest
- FETCH(r1, 2) @ r1<- GFED
+ FETCH(r1, 2) @ r1<- GFED (load here to hide latency)
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ beq .LinvokeArgsDone
- @ r0=methodToCall, r1=GFED, r2=count, r10=outs
+ @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
.LinvokeNonRange:
rsb r2, r2, #5 @ r2<- 5-r2
add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each
bl common_abort @ (skipped due to ARM prefetch)
5: and ip, rINST, #0x0f00 @ isolate A
- ldr r3, [rFP, ip, lsr #6] @ r3<- vA (shift right 8, left 2)
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2)
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vA
+ str r2, [r10, #-4]! @ *--outs = vA
4: and ip, r1, #0xf000 @ isolate G
- ldr r3, [rFP, ip, lsr #10] @ r3<- vG (shift right 12, left 2)
+ ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2)
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vG
+ str r2, [r10, #-4]! @ *--outs = vG
3: and ip, r1, #0x0f00 @ isolate F
- ldr r3, [rFP, ip, lsr #6] @ r3<- vF
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vF
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vF
+ str r2, [r10, #-4]! @ *--outs = vF
2: and ip, r1, #0x00f0 @ isolate E
- ldr r3, [rFP, ip, lsr #2] @ r3<- vE
+ ldr r2, [rFP, ip, lsr #2] @ r2<- vE
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vE
+ str r2, [r10, #-4]! @ *--outs = vE
1: and ip, r1, #0x000f @ isolate D
- ldr r3, [rFP, ip, lsl #2] @ r3<- vD
+ ldr r2, [rFP, ip, lsl #2] @ r2<- vD
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vD
+ str r2, [r10, #-4]! @ *--outs = vD
0: @ fall through to .LinvokeArgsDone
-.LinvokeArgsDone: @ r0=methodToCall
+.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
+ ldr r2, [r0, #offMethod_insns] @ r2<- method->insns
+ ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz
@ find space for the new stack frame, check for overflow
SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
- ldrh r2, [r0, #offMethod_registersSize] @ r2<- methodToCall->regsSize
- ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
- sub r1, r1, r2, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize)
SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea
@ bl common_dumpRegs
ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
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
@ set up newSaveArea
@@ -9474,9 +9849,11 @@
#endif
str rFP, [r10, #offStackSaveArea_prevFrame]
str rPC, [r10, #offStackSaveArea_savedPc]
+#if defined(WITH_JIT)
+ mov r9, #0
+ str r9, [r10, #offStackSaveArea_returnAddr]
+#endif
str r0, [r10, #offStackSaveArea_method]
-
- ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
tst r3, #ACC_NATIVE
bne .LinvokeNative
@@ -9495,19 +9872,31 @@
ldmfd sp!, {r0-r3}
*/
- @ Update "glue" values for the new method
- @ r0=methodToCall, r1=newFp
- ldr r3, [r0, #offMethod_clazz] @ r3<- method->clazz
- str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
- ldr r3, [r3, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
- ldr rPC, [r0, #offMethod_insns] @ rPC<- method->insns
- str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ ldrh r9, [r2] @ r9 <- load INST from new PC
+ ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ mov rPC, r2 @ publish new rPC
ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
- FETCH_INST() @ load rINST from rPC
+
+ @ Update "glue" values for the new method
+ @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
mov rFP, r1 @ fp = newFp
- GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ cmp r0,#0
+ bne common_updateProfile
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
.LinvokeNative:
@ Prep for the native call
@@ -9600,22 +9989,36 @@
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+ ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
@ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
cmp r2, #0 @ is this a break frame?
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
mov r1, #0 @ "want switch" = false
beq common_gotoBail @ break frame, bail out completely
- ldr rPC, [r0, #offStackSaveArea_savedPc] @ pc = saveArea->savedPc
- ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
- str r2, [rGLUE, #offGlue_method] @ glue->method = newSave->method
+ PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
- ldr r1, [r2, #offMethod_clazz] @ r1<- method->clazz
- FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
- ldr r1, [r1, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+#if defined(WITH_JIT)
+ ldr r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr
+ GET_JIT_PROF_TABLE(r0)
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r3, #0 @ caller is compiled code
+ blxne r3
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
+ mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/*
* Return handling, calls through "glue code".
@@ -9638,12 +10041,19 @@
*
* This does not return.
*/
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
common_exceptionThrown:
.LexceptionNew:
mov r0, #kInterpEntryThrow
mov r9, #0
bl common_periodicChecks
+#if defined(WITH_JIT)
+ mov r2,#kJitTSelectAbort @ abandon trace selection in progress
+ str r2,[rGLUE,#offGlue_jitState]
+#endif
+
ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self
ldr r9, [r10, #offThread_exception] @ r9<- self->exception
mov r1, r10 @ r1<- self
@@ -9925,6 +10335,38 @@
bx lr
.endif
+#if 0
+/*
+ * Experiment on VFP mode.
+ *
+ * uint32_t setFPSCR(uint32_t val, uint32_t mask)
+ *
+ * Updates the bits specified by "mask", setting them to the values in "val".
+ */
+setFPSCR:
+ and r0, r0, r1 @ make sure no stray bits are set
+ fmrx r2, fpscr @ get VFP reg
+ mvn r1, r1 @ bit-invert mask
+ and r2, r2, r1 @ clear masked bits
+ orr r2, r2, r0 @ set specified bits
+ fmxr fpscr, r2 @ set VFP reg
+ mov r0, r2 @ return new value
+ bx lr
+
+ .align 2
+ .global dvmConfigureFP
+ .type dvmConfigureFP, %function
+dvmConfigureFP:
+ stmfd sp!, {ip, lr}
+ /* 0x03000000 sets DN/FZ */
+ /* 0x00009f00 clears the six exception enable flags */
+ bl common_squeak0
+ mov r0, #0x03000000 @ r0<- 0x03000000
+ add r1, r0, #0x9f00 @ r1<- 0x03009f00
+ bl setFPSCR
+ ldmfd sp!, {ip, pc}
+#endif
+
/*
* String references, must be close to the code that uses them.
diff --git a/vm/mterp/out/InterpAsm-armv5te-vfp.S b/vm/mterp/out/InterpAsm-armv5te-vfp.S
new file mode 100644
index 0000000..5a8ae4c
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv5te-vfp.S
@@ -0,0 +1,9972 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv5te-vfp'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: armv5te/header.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.
+ */
+/*
+ * ARMv5 definitions and declarations.
+ */
+
+/*
+ARM EABI general notes:
+
+r0-r3 hold first 4 args to a method; they are not preserved across method calls
+r4-r8 are available for general use
+r9 is given special treatment in some situations, but not for us
+r10 (sl) seems to be generally available
+r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
+r12 (ip) is scratch -- not preserved across method calls
+r13 (sp) should be managed carefully in case a signal arrives
+r14 (lr) must be preserved
+r15 (pc) can be tinkered with directly
+
+r0 holds returns of <= 4 bytes
+r0-r1 hold returns of 8 bytes, low word in r0
+
+Callee must save/restore r4+ (except r12) if it modifies them. If VFP
+is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
+s0-s15 (d0-d7, q0-a3) do not need to be.
+
+Stack is "full descending". Only the arguments that don't fit in the first 4
+registers are placed on the stack. "sp" points at the first stacked argument
+(i.e. the 5th arg).
+
+VFP: single-precision results in s0, double-precision results in d0.
+
+In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
+64-bit quantities (long long, double) must be 64-bit aligned.
+*/
+
+/*
+Mterp and ARM notes:
+
+The following registers have fixed assignments:
+
+ reg nick purpose
+ r4 rPC interpreted program counter, used for fetching instructions
+ r5 rFP interpreted frame pointer, used for accessing locals and args
+ r6 rGLUE MterpGlue pointer
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
+
+Macros are provided for common operations. Each macro MUST emit only
+one instruction to make instruction-counting easier. They MUST NOT alter
+unspecified registers or condition codes.
+*/
+
+/* single-purpose registers, given names for clarity */
+#define rPC r4
+#define rFP r5
+#define rGLUE r6
+#define rINST r7
+#define rIBASE r8
+
+/* save/restore the PC and/or FP from the glue struct */
+#define LOAD_PC_FROM_GLUE() ldr rPC, [rGLUE, #offGlue_pc]
+#define SAVE_PC_TO_GLUE() str rPC, [rGLUE, #offGlue_pc]
+#define LOAD_FP_FROM_GLUE() ldr rFP, [rGLUE, #offGlue_fp]
+#define SAVE_FP_TO_GLUE() str rFP, [rGLUE, #offGlue_fp]
+#define LOAD_PC_FP_FROM_GLUE() ldmia rGLUE, {rPC, rFP}
+#define SAVE_PC_FP_TO_GLUE() stmia rGLUE, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects. Must
+ * be done *before* something calls dvmThrowException.
+ *
+ * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
+ * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
+ *
+ * It's okay to do this more than once.
+ */
+#define EXPORT_PC() \
+ str rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+#define SAVEAREA_FROM_FP(_reg, _fpreg) \
+ sub _reg, _fpreg, #sizeofStackSaveArea
+
+/*
+ * Fetch the next instruction from rPC into rINST. Does not advance rPC.
+ */
+#define FETCH_INST() ldrh rINST, [rPC]
+
+/*
+ * Fetch the next instruction from the specified offset. Advances rPC
+ * to point to the next instruction. "_count" is in 16-bit code units.
+ *
+ * Because of the limited size of immediate constants on ARM, this is only
+ * suitable for small forward movements (i.e. don't try to implement "goto"
+ * with this).
+ *
+ * This must come AFTER anything that can throw an exception, or the
+ * exception catch may miss. (This also implies that it must come after
+ * EXPORT_PC().)
+ */
+#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!
+
+/*
+ * The operation performed here is similar to FETCH_ADVANCE_INST, except the
+ * src and dest registers are parameterized (not hard-wired to rPC and rINST).
+ */
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ ldrh _dreg, [_sreg, #(_count*2)]!
+
+/*
+ * Fetch the next instruction from an offset specified by _reg. Updates
+ * rPC to point to the next instruction. "_reg" must specify the distance
+ * in bytes, *not* 16-bit code units, and may be a signed value.
+ *
+ * We want to write "ldrh rINST, [rPC, _reg, lsl #2]!", but some of the
+ * bits that hold the shift distance are used for the half/byte/sign flags.
+ * In some cases we can pre-double _reg for free, so we require a byte offset
+ * here.
+ */
+#define FETCH_ADVANCE_INST_RB(_reg) ldrh rINST, [rPC, _reg]!
+
+/*
+ * Fetch a half-word code unit from an offset past the current PC. The
+ * "_count" value is in 16-bit code units. Does not advance rPC.
+ *
+ * The "_S" variant works the same but treats the value as signed.
+ */
+#define FETCH(_reg, _count) ldrh _reg, [rPC, #(_count*2)]
+#define FETCH_S(_reg, _count) ldrsh _reg, [rPC, #(_count*2)]
+
+/*
+ * Fetch one byte from an offset past the current PC. Pass in the same
+ * "_count" as you would for FETCH, and an additional 0/1 indicating which
+ * byte of the halfword you want (lo/hi).
+ */
+#define FETCH_B(_reg, _count, _byte) ldrb _reg, [rPC, #(_count*2+_byte)]
+
+/*
+ * Put the instruction's opcode field into the specified register.
+ */
+#define GET_INST_OPCODE(_reg) and _reg, rINST, #255
+
+/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+#define GET_PREFETCHED_OPCODE(_oreg, _ireg) and _oreg, _ireg, #255
+
+/*
+ * Begin executing the opcode in _reg. Because this only jumps within the
+ * interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
+ */
+#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFEQ(_reg) addeq pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFNE(_reg) addne pc, rIBASE, _reg, lsl #6
+
+/*
+ * Get/set the 32-bit value from a Dalvik register.
+ */
+#define GET_VREG(_reg, _vreg) ldr _reg, [rFP, _vreg, lsl #2]
+#define SET_VREG(_reg, _vreg) str _reg, [rFP, _vreg, lsl #2]
+
+#if defined(WITH_JIT)
+#define GET_JIT_ENABLED(_reg) ldr _reg,[rGLUE,#offGlue_jitEnabled]
+#define GET_JIT_PROF_TABLE(_reg) ldr _reg,[rGLUE,#offGlue_pJitProfTable]
+#endif
+
+/*
+ * Convert a virtual register index into an address.
+ */
+#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
+ add _reg, rFP, _vreg, lsl #2
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../common/asm-constants.h"
+
+
+/* File: armv5te/platform.S */
+/*
+ * ===========================================================================
+ * 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
+
+
+/* File: armv5te/entry.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.
+ */
+/*
+ * Interpreter entry point.
+ */
+
+/*
+ * We don't have formal stack frames, so gdb scans upward in the code
+ * to find the start of the function (a label with the %function type),
+ * and then looks at the next few instructions to figure out what
+ * got pushed onto the stack. From this it figures out how to restore
+ * the registers, including PC, for the previous stack frame. If gdb
+ * sees a non-function label, it stops scanning, so either we need to
+ * have nothing but assembler-local labels between the entry point and
+ * the break, or we need to fake it out.
+ *
+ * When this is defined, we add some stuff to make gdb less confused.
+ */
+#define ASSIST_DEBUGGER 1
+
+ .text
+ .align 2
+ .global dvmMterpStdRun
+ .type dvmMterpStdRun, %function
+
+/*
+ * On entry:
+ * r0 MterpGlue* glue
+ *
+ * This function returns a boolean "changeInterp" value. The return comes
+ * via a call to dvmMterpStdBail().
+ */
+dvmMterpStdRun:
+#define MTERP_ENTRY1 \
+ .save {r4-r10,fp,lr}; \
+ stmfd sp!, {r4-r10,fp,lr} @ save 9 regs
+#define MTERP_ENTRY2 \
+ .pad #4; \
+ sub sp, sp, #4 @ align 64
+
+ .fnstart
+ MTERP_ENTRY1
+ MTERP_ENTRY2
+
+ /* save stack pointer, add magic word for debuggerd */
+ str sp, [r0, #offGlue_bailPtr] @ save SP for eventual return
+
+ /* set up "named" registers, figure out entry point */
+ mov rGLUE, r0 @ set rGLUE
+ ldrb r1, [r0, #offGlue_entryPoint] @ InterpEntry enum is char
+ LOAD_PC_FP_FROM_GLUE() @ load rPC and rFP from "glue"
+ adr rIBASE, dvmAsmInstructionStart @ set rIBASE
+ cmp r1, #kInterpEntryInstr @ usual case?
+ bne .Lnot_instr @ no, handle it
+
+#if defined(WITH_JIT)
+.Lno_singleStep:
+ /* Entry is always a possible trace start */
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
+ /* start executing the instruction at rPC */
+ FETCH_INST() @ load rINST from rPC
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+.Lnot_instr:
+ cmp r1, #kInterpEntryReturn @ were we returning from a method?
+ beq common_returnFromMethod
+
+.Lnot_return:
+ cmp r1, #kInterpEntryThrow @ were we throwing an exception?
+ beq common_exceptionThrown
+
+#if defined(WITH_JIT)
+.Lnot_throw:
+ ldr r0,[rGLUE, #offGlue_jitResume]
+ ldr r2,[rGLUE, #offGlue_jitResumePC]
+ cmp r1, #kInterpEntryResume @ resuming after Jit single-step?
+ bne .Lbad_arg
+ cmp rPC,r2
+ bne .Lno_singleStep @ must have branched, don't resume
+ mov r1, #kInterpEntryInstr
+ strb r1, [rGLUE, #offGlue_entryPoint]
+ ldr rINST, .LdvmCompilerTemplate
+ bx r0 @ re-enter the translation
+.LdvmCompilerTemplate:
+ .word dvmCompilerTemplateStart
+#endif
+
+.Lbad_arg:
+ ldr r0, strBadEntryPoint
+ @ r1 holds value of entryPoint
+ bl printf
+ bl dvmAbort
+ .fnend
+
+
+ .global dvmMterpStdBail
+ .type dvmMterpStdBail, %function
+
+/*
+ * Restore the stack pointer and PC from the save point established on entry.
+ * This is essentially the same as a longjmp, but should be cheaper. The
+ * last instruction causes us to return to whoever called dvmMterpStdRun.
+ *
+ * We pushed some registers on the stack in dvmMterpStdRun, then saved
+ * SP and LR. Here we restore SP, restore the registers, and then restore
+ * LR to PC.
+ *
+ * On entry:
+ * r0 MterpGlue* glue
+ * r1 bool changeInterp
+ */
+dvmMterpStdBail:
+ ldr sp, [r0, #offGlue_bailPtr] @ sp<- saved SP
+ mov r0, r1 @ return the changeInterp value
+ add sp, sp, #4 @ un-align 64
+ LDMFD_PC "r4-r10,fp" @ restore 9 regs and return
+
+
+/*
+ * String references.
+ */
+strBadEntryPoint:
+ .word .LstrBadEntryPoint
+
+
+
+ .global dvmAsmInstructionStart
+ .type dvmAsmInstructionStart, %function
+dvmAsmInstructionStart = .L_OP_NOP
+ .text
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NOP: /* 0x00 */
+/* File: armv5te/OP_NOP.S */
+ FETCH_ADVANCE_INST(1) @ advance to next instr, load rINST
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ .type dalvik_inst, %function
+dalvik_inst:
+ .fnstart
+ MTERP_ENTRY1
+ MTERP_ENTRY2
+ .fnend
+#endif
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE: /* 0x01 */
+/* File: armv5te/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ mov r0, rINST, lsr #8 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ and r0, r0, #15
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r2, r0) @ fp[A]<- r2
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/OP_MOVE_FROM16.S */
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ mov r0, rINST, lsr #8 @ r0<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/OP_MOVE_16.S */
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(r1, 2) @ r1<- BBBB
+ FETCH(r0, 1) @ r0<- AAAA
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AAAA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv5te/OP_MOVE_WIDE.S */
+ /* move-wide vA, vB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ mov r2, rINST, lsr #8 @ r2<- A(+)
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r2, r2, #15
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[B]
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/OP_MOVE_WIDE_FROM16.S */
+ /* move-wide/from16 vAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ FETCH(r3, 1) @ r3<- BBBB
+ mov r2, rINST, lsr #8 @ r2<- AA
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[AA]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/OP_MOVE_WIDE_16.S */
+ /* move-wide/16 vAAAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ FETCH(r3, 2) @ r3<- BBBB
+ FETCH(r2, 1) @ r2<- AAAA
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AAAA]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/OP_MOVE_OBJECT.S */
+/* File: armv5te/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ mov r0, rINST, lsr #8 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ and r0, r0, #15
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r2, r0) @ fp[A]<- r2
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/OP_MOVE_OBJECT_FROM16.S */
+/* File: armv5te/OP_MOVE_FROM16.S */
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ mov r0, rINST, lsr #8 @ r0<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/OP_MOVE_OBJECT_16.S */
+/* File: armv5te/OP_MOVE_16.S */
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(r1, 2) @ r1<- BBBB
+ FETCH(r0, 1) @ r0<- AAAA
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AAAA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/OP_MOVE_RESULT.S */
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- glue->retval.i
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[AA]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/OP_MOVE_RESULT_WIDE.S */
+ /* move-result-wide vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ add r3, rGLUE, #offGlue_retval @ r3<- &glue->retval
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
+ ldmia r3, {r0-r1} @ r0/r1<- retval.j
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[AA]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/OP_MOVE_RESULT_OBJECT.S */
+/* File: armv5te/OP_MOVE_RESULT.S */
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- glue->retval.i
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[AA]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/OP_MOVE_EXCEPTION.S */
+ /* move-exception vAA */
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ mov r2, rINST, lsr #8 @ r2<- AA
+ ldr r3, [r0, #offThread_exception] @ r3<- dvmGetException bypass
+ mov r1, #0 @ r1<- 0
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ SET_VREG(r3, r2) @ fp[AA]<- exception obj
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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 */
+/* File: armv5te/OP_RETURN.S */
+ /*
+ * Return a 32-bit value. Copies the return value into the "glue"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r0, r2) @ r0<- vAA
+ str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/OP_RETURN_WIDE.S */
+ /*
+ * Return a 64-bit value. Copies the return value into the "glue"
+ * structure, then jumps to the return handler.
+ */
+ /* return-wide vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
+ add r3, rGLUE, #offGlue_retval @ r3<- &glue->retval
+ ldmia r2, {r0-r1} @ r0/r1 <- vAA/vAA+1
+ stmia r3, {r0-r1} @ retval<- r0/r1
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/OP_RETURN_OBJECT.S */
+/* File: armv5te/OP_RETURN.S */
+ /*
+ * Return a 32-bit value. Copies the return value into the "glue"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r0, r2) @ r0<- vAA
+ str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
+ b common_returnFromMethod
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_4: /* 0x12 */
+/* File: armv5te/OP_CONST_4.S */
+ /* const/4 vA, #+B */
+ mov r1, rINST, lsl #16 @ r1<- Bxxx0000
+ mov r0, rINST, lsr #8 @ r0<- A+
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r1, r1, asr #28 @ r1<- sssssssB (sign-extended)
+ and r0, r0, #15
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r1, r0) @ fp[A]<- r1
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_16: /* 0x13 */
+/* File: armv5te/OP_CONST_16.S */
+ /* const/16 vAA, #+BBBB */
+ FETCH_S(r0, 1) @ r0<- ssssBBBB (sign-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST: /* 0x14 */
+/* File: armv5te/OP_CONST.S */
+ /* const vAA, #+BBBBbbbb */
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH(r0, 1) @ r0<- bbbb (low)
+ FETCH(r1, 2) @ r1<- BBBB (high)
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/OP_CONST_HIGH16.S */
+ /* const/high16 vAA, #+BBBB0000 */
+ FETCH(r0, 1) @ r0<- 0000BBBB (zero-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ mov r0, r0, lsl #16 @ r0<- BBBB0000
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/OP_CONST_WIDE_16.S */
+ /* const-wide/16 vAA, #+BBBB */
+ FETCH_S(r0, 1) @ r0<- ssssBBBB (sign-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ mov r1, r0, asr #31 @ r1<- ssssssss
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/OP_CONST_WIDE_32.S */
+ /* const-wide/32 vAA, #+BBBBbbbb */
+ FETCH(r0, 1) @ r0<- 0000bbbb (low)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH_S(r2, 2) @ r2<- ssssBBBB (high)
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ orr r0, r0, r2, lsl #16 @ r0<- BBBBbbbb
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
+ mov r1, r0, asr #31 @ r1<- ssssssss
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/OP_CONST_WIDE.S */
+ /* const-wide vAA, #+HHHHhhhhBBBBbbbb */
+ FETCH(r0, 1) @ r0<- bbbb (low)
+ FETCH(r1, 2) @ r1<- BBBB (low middle)
+ FETCH(r2, 3) @ r2<- hhhh (high middle)
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb (low word)
+ FETCH(r3, 4) @ r3<- HHHH (high)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ orr r1, r2, r3, lsl #16 @ r1<- HHHHhhhh (high word)
+ FETCH_ADVANCE_INST(5) @ advance rPC, load rINST
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/OP_CONST_WIDE_HIGH16.S */
+ /* const-wide/high16 vAA, #+BBBB000000000000 */
+ FETCH(r1, 1) @ r1<- 0000BBBB (zero-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ mov r0, #0 @ r0<- 00000000
+ mov r1, r1, lsl #16 @ r1<- BBBB0000
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/OP_CONST_STRING.S */
+ /* const/string vAA, String@BBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r2, #offDvmDex_pResStrings] @ r2<- dvmDex->pResStrings
+ ldr r0, [r2, r1, lsl #2] @ r0<- pResStrings[BBBB]
+ cmp r0, #0 @ not yet resolved?
+ beq .LOP_CONST_STRING_resolve
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/OP_CONST_STRING_JUMBO.S */
+ /* const/string vAA, String@BBBBBBBB */
+ FETCH(r0, 1) @ r0<- bbbb (low)
+ FETCH(r1, 2) @ r1<- BBBB (high)
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r2, #offDvmDex_pResStrings] @ r2<- dvmDex->pResStrings
+ orr r1, r0, r1, lsl #16 @ r1<- BBBBbbbb
+ ldr r0, [r2, r1, lsl #2] @ r0<- pResStrings[BBBB]
+ cmp r0, #0
+ beq .LOP_CONST_STRING_JUMBO_resolve
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/OP_CONST_CLASS.S */
+ /* const/class vAA, Class@BBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r2, #offDvmDex_pResClasses] @ r2<- dvmDex->pResClasses
+ ldr r0, [r2, r1, lsl #2] @ r0<- pResClasses[BBBB]
+ cmp r0, #0 @ not yet resolved?
+ beq .LOP_CONST_CLASS_resolve
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/OP_MONITOR_ENTER.S */
+ /*
+ * Synchronize on an object.
+ */
+ /* monitor-enter vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r1, r2) @ r1<- vAA (object)
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ cmp r1, #0 @ null object?
+ EXPORT_PC() @ need for precise GC, MONITOR_TRACKING
+ beq common_errNullObject @ null object, throw an exception
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ bl dvmLockObject @ call(self, obj)
+#ifdef WITH_DEADLOCK_PREDICTION /* implies WITH_MONITOR_TRACKING */
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ ldr r1, [r0, #offThread_exception] @ check for exception
+ cmp r1, #0
+ bne common_exceptionThrown @ exception raised, bail out
+#endif
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/OP_MONITOR_EXIT.S */
+ /*
+ * Unlock an object.
+ *
+ * Exceptions that occur when unlocking a monitor need to appear as
+ * if they happened at the following instruction. See the Dalvik
+ * instruction spec.
+ */
+ /* monitor-exit vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ EXPORT_PC() @ before fetch: export the PC
+ GET_VREG(r1, r2) @ r1<- vAA (object)
+ cmp r1, #0 @ null object?
+ beq common_errNullObject @ yes
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ bl dvmUnlockObject @ r0<- success for unlock(self, obj)
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yes, exception is pending
+ FETCH_ADVANCE_INST(1) @ before throw: advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CHECK_CAST: /* 0x1f */
+/* File: armv5te/OP_CHECK_CAST.S */
+ /*
+ * Check to see if a cast from one class to another is allowed.
+ */
+ /* check-cast vAA, class@BBBB */
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH(r2, 1) @ r2<- BBBB
+ GET_VREG(r9, r3) @ r9<- object
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- pDvmDex
+ cmp r9, #0 @ is object null?
+ ldr r0, [r0, #offDvmDex_pResClasses] @ r0<- pDvmDex->pResClasses
+ beq .LOP_CHECK_CAST_okay @ null obj, cast always succeeds
+ ldr r1, [r0, r2, lsl #2] @ r1<- resolved class
+ ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
+ cmp r1, #0 @ have we resolved this before?
+ beq .LOP_CHECK_CAST_resolve @ not resolved, do it now
+.LOP_CHECK_CAST_resolved:
+ cmp r0, r1 @ same class (trivial success)?
+ bne .LOP_CHECK_CAST_fullcheck @ no, do full check
+.LOP_CHECK_CAST_okay:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/OP_INSTANCE_OF.S */
+ /*
+ * Check to see if an object reference is an instance of a class.
+ *
+ * Most common situation is a non-null object, being compared against
+ * an already-resolved class.
+ */
+ /* instance-of vA, vB, class@CCCC */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB (object)
+ and r9, r9, #15 @ r9<- A
+ cmp r0, #0 @ is object null?
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- pDvmDex
+ beq .LOP_INSTANCE_OF_store @ null obj, not an instance, store r0
+ FETCH(r3, 1) @ r3<- CCCC
+ ldr r2, [r2, #offDvmDex_pResClasses] @ r2<- pDvmDex->pResClasses
+ ldr r1, [r2, r3, lsl #2] @ r1<- resolved class
+ ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
+ cmp r1, #0 @ have we resolved this before?
+ beq .LOP_INSTANCE_OF_resolve @ not resolved, do it now
+.LOP_INSTANCE_OF_resolved: @ r0=obj->clazz, r1=resolved class
+ cmp r0, r1 @ same class (trivial success)?
+ beq .LOP_INSTANCE_OF_trivial @ yes, trivial finish
+ b .LOP_INSTANCE_OF_fullcheck @ no, do full check
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv5te/OP_ARRAY_LENGTH.S */
+ /*
+ * Return the length of an array.
+ */
+ mov r1, rINST, lsr #12 @ r1<- B
+ mov r2, rINST, lsr #8 @ r2<- A+
+ GET_VREG(r0, r1) @ r0<- vB (object ref)
+ and r2, r2, #15 @ r2<- A
+ cmp r0, #0 @ is object null?
+ beq common_errNullObject @ yup, fail
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r3, [r0, #offArrayObject_length] @ r3<- array length
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r3, r2) @ vB<- length
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/OP_NEW_INSTANCE.S */
+ /*
+ * Create a new instance of a class.
+ */
+ /* new-instance vAA, class@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
+ EXPORT_PC() @ req'd for init, resolve, alloc
+ cmp r0, #0 @ already resolved?
+ beq .LOP_NEW_INSTANCE_resolve @ no, resolve it now
+.LOP_NEW_INSTANCE_resolved: @ r0=class
+ ldrb r1, [r0, #offClassObject_status] @ r1<- ClassStatus enum
+ cmp r1, #CLASS_INITIALIZED @ has class been initialized?
+ bne .LOP_NEW_INSTANCE_needinit @ no, init class now
+.LOP_NEW_INSTANCE_initialized: @ r0=class
+ mov r1, #ALLOC_DONT_TRACK @ flags for alloc call
+ bl dvmAllocObject @ r0<- new object
+ b .LOP_NEW_INSTANCE_finish @ continue
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/OP_NEW_ARRAY.S */
+ /*
+ * Allocate an array of objects, specified with the array class
+ * and a count.
+ *
+ * The verifier guarantees that this is an array class, so we don't
+ * check for it here.
+ */
+ /* new-array vA, vB, class@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ FETCH(r2, 1) @ r2<- CCCC
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ GET_VREG(r1, r0) @ r1<- vB (array length)
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ cmp r1, #0 @ check length
+ ldr r0, [r3, r2, lsl #2] @ r0<- resolved class
+ bmi common_errNegativeArraySize @ negative length, bail
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ req'd for resolve, alloc
+ bne .LOP_NEW_ARRAY_finish @ resolved, continue
+ b .LOP_NEW_ARRAY_resolve @ do resolve now
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ EXPORT_PC() @ need for resolve and alloc
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
+ mov r10, rINST, lsr #8 @ r10<- AA or BA
+ cmp r0, #0 @ already resolved?
+ bne .LOP_FILLED_NEW_ARRAY_continue @ yes, continue on
+8: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- call(clazz, ref)
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ b .LOP_FILLED_NEW_ARRAY_continue
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_RANGE.S */
+/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ EXPORT_PC() @ need for resolve and alloc
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
+ mov r10, rINST, lsr #8 @ r10<- AA or BA
+ cmp r0, #0 @ already resolved?
+ bne .LOP_FILLED_NEW_ARRAY_RANGE_continue @ yes, continue on
+8: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- call(clazz, ref)
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ b .LOP_FILLED_NEW_ARRAY_RANGE_continue
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/OP_FILL_ARRAY_DATA.S */
+ /* fill-array-data vAA, +BBBBBBBB */
+ FETCH(r0, 1) @ r0<- bbbb (lo)
+ FETCH(r1, 2) @ r1<- BBBB (hi)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ orr r1, r0, r1, lsl #16 @ r1<- BBBBbbbb
+ GET_VREG(r0, r3) @ r0<- vAA (array object)
+ add r1, rPC, r1, lsl #1 @ r1<- PC + BBBBbbbb*2 (array data off.)
+ EXPORT_PC();
+ bl dvmInterpHandleFillArrayData@ fill the array with predefined data
+ cmp r0, #0 @ 0 means an exception is thrown
+ beq common_exceptionThrown @ has exception
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_THROW: /* 0x27 */
+/* File: armv5te/OP_THROW.S */
+ /*
+ * Throw an exception object in the current thread.
+ */
+ /* throw vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r1, r2) @ r1<- vAA (exception object)
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ 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 */
+/* File: armv5te/OP_GOTO.S */
+ /*
+ * Unconditional branch, 8-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto +AA */
+ mov r0, rINST, lsl #16 @ r0<- AAxx0000
+ movs r9, r0, asr #24 @ r9<- ssssssAA (sign-extended)
+ mov r9, r9, lsl #1 @ r9<- byte offset
+ bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/OP_GOTO_16.S */
+ /*
+ * Unconditional branch, 16-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto/16 +AAAA */
+ FETCH_S(r0, 1) @ r0<- ssssAAAA (sign-extended)
+ movs r9, r0, asl #1 @ r9<- byte offset, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/OP_GOTO_32.S */
+ /*
+ * Unconditional branch, 32-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ *
+ * Unlike most opcodes, this one is allowed to branch to itself, so
+ * our "backward branch" test must be "<=0" instead of "<0". The ORRS
+ * instruction doesn't affect the V flag, so we need to clear it
+ * explicitly.
+ */
+ /* goto/32 +AAAAAAAA */
+ FETCH(r0, 1) @ r0<- aaaa (lo)
+ FETCH(r1, 2) @ r1<- AAAA (hi)
+ cmp ip, ip @ (clear V flag during stall)
+ orrs r0, r0, r1, lsl #16 @ r0<- AAAAaaaa, check sign
+ mov r9, r0, asl #1 @ r9<- byte offset
+ ble common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/OP_PACKED_SWITCH.S */
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(r0, 1) @ r0<- bbbb (lo)
+ FETCH(r1, 2) @ r1<- BBBB (hi)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
+ GET_VREG(r1, r3) @ r1<- vAA
+ add r0, rPC, r0, lsl #1 @ r0<- PC + BBBBbbbb*2
+ bl dvmInterpHandlePackedSwitch @ r0<- code-unit branch offset
+ movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+ beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/OP_SPARSE_SWITCH.S */
+/* File: armv5te/OP_PACKED_SWITCH.S */
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(r0, 1) @ r0<- bbbb (lo)
+ FETCH(r1, 2) @ r1<- BBBB (hi)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
+ GET_VREG(r1, r3) @ r1<- vAA
+ add r0, rPC, r0, lsl #1 @ r0<- PC + BBBBbbbb*2
+ bl dvmInterpHandleSparseSwitch @ r0<- code-unit branch offset
+ movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+ beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: arm-vfp/OP_CMPL_FLOAT.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ flds s0, [r2] @ s0<- vBB
+ flds s1, [r3] @ s1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mvn r0, #0 @ r0<- -1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r1<- 1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPL_FLOAT_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: arm-vfp/OP_CMPG_FLOAT.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ flds s0, [r2] @ s0<- vBB
+ flds s1, [r3] @ s1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mov r0, #1 @ r0<- 1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPG_FLOAT_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: arm-vfp/OP_CMPL_DOUBLE.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ fldd d0, [r2] @ d0<- vBB
+ fldd d1, [r3] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mvn r0, #0 @ r0<- -1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r1<- 1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPL_DOUBLE_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: arm-vfp/OP_CMPG_DOUBLE.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ fldd d0, [r2] @ d0<- vBB
+ fldd d1, [r3] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mov r0, #1 @ r0<- 1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPG_DOUBLE_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/OP_CMP_LONG.S */
+ /*
+ * Compare two 64-bit values. Puts 0, 1, or -1 into the destination
+ * register based on the results of the comparison.
+ *
+ * We load the full values with LDM, but in practice many values could
+ * be resolved by only looking at the high word. This could be made
+ * faster or slower by splitting the LDM into a pair of LDRs.
+ *
+ * If we just wanted to set condition flags, we could do this:
+ * subs ip, r0, r2
+ * sbcs ip, r1, r3
+ * subeqs ip, r0, r2
+ * Leaving { <0, 0, >0 } in ip. However, we have to set it to a specific
+ * integer value, which we can do with 2 conditional mov/mvn instructions
+ * (set 1, set -1; if they're equal we already have 0 in ip), giving
+ * us a constant 5-cycle path plus a branch at the end to the
+ * instruction epilogue code. The multi-compare approach below needs
+ * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
+ * in the worst case (the 64-bit values are equal).
+ */
+ /* cmp-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ cmp r1, r3 @ compare (vBB+1, vCC+1)
+ blt .LOP_CMP_LONG_less @ signed compare on high part
+ bgt .LOP_CMP_LONG_greater
+ subs r1, r0, r2 @ r1<- r0 - r2
+ bhi .LOP_CMP_LONG_greater @ unsigned compare on low part
+ bne .LOP_CMP_LONG_less
+ b .LOP_CMP_LONG_finish @ equal; r1 already holds 0
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_EQ: /* 0x32 */
+/* File: armv5te/OP_IF_EQ.S */
+/* File: armv5te/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ bne 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_NE: /* 0x33 */
+/* File: armv5te/OP_IF_NE.S */
+/* File: armv5te/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ beq 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LT: /* 0x34 */
+/* File: armv5te/OP_IF_LT.S */
+/* File: armv5te/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ bge 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GE: /* 0x35 */
+/* File: armv5te/OP_IF_GE.S */
+/* File: armv5te/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ blt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GT: /* 0x36 */
+/* File: armv5te/OP_IF_GT.S */
+/* File: armv5te/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ ble 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LE: /* 0x37 */
+/* File: armv5te/OP_IF_LE.S */
+/* File: armv5te/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ bgt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/OP_IF_EQZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ bne 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/OP_IF_NEZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ beq 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/OP_IF_LTZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ bge 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/OP_IF_GEZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ blt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/OP_IF_GTZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ ble 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/OP_IF_LEZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ bgt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/OP_UNUSED_3E.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/OP_UNUSED_3F.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/OP_UNUSED_40.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/OP_UNUSED_41.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/OP_UNUSED_42.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/OP_UNUSED_43.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET: /* 0x44 */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/OP_AGET_WIDE.S */
+ /*
+ * Array get, 64 bits. vAA <- vBB[vCC].
+ *
+ * Arrays of long/double are 64-bit aligned, so it's okay to use LDRD.
+ */
+ /* aget-wide vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #3 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcc .LOP_AGET_WIDE_finish @ okay, continue below
+ b common_errArrayIndex @ index >= length, bail
+ @ May want to swap the order of these two branches depending on how the
+ @ branch prediction (if any) handles conditional forward branches vs.
+ @ unconditional forward branches.
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/OP_AGET_OBJECT.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/OP_AGET_BOOLEAN.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrb r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/OP_AGET_BYTE.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrsb r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/OP_AGET_CHAR.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrh r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/OP_AGET_SHORT.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrsh r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT: /* 0x4b */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/OP_APUT_WIDE.S */
+ /*
+ * Array put, 64 bits. vBB[vCC] <- vAA.
+ *
+ * Arrays of long/double are 64-bit aligned, so it's okay to use STRD.
+ */
+ /* aput-wide vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #3 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ bcc .LOP_APUT_WIDE_finish @ okay, continue below
+ b common_errArrayIndex @ index >= length, bail
+ @ May want to swap the order of these two branches depending on how the
+ @ branch prediction (if any) handles conditional forward branches vs.
+ @ unconditional forward branches.
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/OP_APUT_OBJECT.S */
+ /*
+ * Store an object into an array. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ GET_VREG(r1, r2) @ r1<- vBB (array object)
+ GET_VREG(r0, r3) @ r0<- vCC (requested index)
+ cmp r1, #0 @ null array object?
+ GET_VREG(r9, r9) @ r9<- vAA
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r1, #offArrayObject_length] @ r3<- arrayObj->length
+ add r10, r1, r0, lsl #2 @ r10<- arrayObj + index*width
+ cmp r0, r3 @ compare unsigned index, length
+ bcc .LOP_APUT_OBJECT_finish @ we're okay, continue on
+ b common_errArrayIndex @ index >= length, bail
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/OP_APUT_BOOLEAN.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strb r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/OP_APUT_BYTE.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strb r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/OP_APUT_CHAR.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strh r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/OP_APUT_SHORT.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strh r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET: /* 0x52 */
+/* 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_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_finish
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_WIDE: /* 0x53 */
+/* 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_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_finish
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/OP_IGET_OBJECT.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_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_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/OP_IGET_BOOLEAN.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrb", "sqnum":"1" }
+/* 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_BOOLEAN_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_BOOLEAN_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/OP_IGET_BYTE.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrsb", "sqnum":"2" }
+/* 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_BYTE_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_BYTE_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/OP_IGET_CHAR.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrh", "sqnum":"3" }
+/* 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_CHAR_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_CHAR_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/OP_IGET_SHORT.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrsh", "sqnum":"4" }
+/* 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_SHORT_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_SHORT_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT: /* 0x59 */
+/* File: armv5te/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 */
+ 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_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_finish @ yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_WIDE: /* 0x5a */
+/* 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_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_finish @ yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+/* File: armv5te/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 */
+ 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_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_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/OP_IPUT_BOOLEAN.S */
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/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 */
+ 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_BOOLEAN_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_BOOLEAN_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/OP_IPUT_BYTE.S */
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/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 */
+ 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_BYTE_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_BYTE_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/OP_IPUT_CHAR.S */
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/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 */
+ 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_CHAR_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_CHAR_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/OP_IPUT_SHORT.S */
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/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 */
+ 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_SHORT_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_SHORT_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SGET: /* 0x60 */
+/* 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_resolve @ yes, do resolve
+.LOP_SGET_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_WIDE: /* 0x61 */
+/* 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_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]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/OP_SGET_OBJECT.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_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/OP_SGET_BOOLEAN.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_BOOLEAN_resolve @ yes, do resolve
+.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_BYTE: /* 0x64 */
+/* File: armv5te/OP_SGET_BYTE.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_BYTE_resolve @ yes, do resolve
+.LOP_SGET_BYTE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_CHAR: /* 0x65 */
+/* File: armv5te/OP_SGET_CHAR.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_CHAR_resolve @ yes, do resolve
+.LOP_SGET_CHAR_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_SHORT: /* 0x66 */
+/* File: armv5te/OP_SGET_SHORT.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_SHORT_resolve @ yes, do resolve
+.LOP_SGET_SHORT_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SPUT: /* 0x67 */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_resolve @ yes, do resolve
+.LOP_SPUT_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
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-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
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r0, 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
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/OP_SPUT_BOOLEAN.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_BOOLEAN_resolve @ yes, do resolve
+.LOP_SPUT_BOOLEAN_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/OP_SPUT_BYTE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_BYTE_resolve @ yes, do resolve
+.LOP_SPUT_BYTE_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/OP_SPUT_CHAR.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_CHAR_resolve @ yes, do resolve
+.LOP_SPUT_CHAR_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/OP_SPUT_SHORT.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_SHORT_resolve @ yes, do resolve
+.LOP_SPUT_SHORT_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/OP_INVOKE_VIRTUAL.S */
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_VIRTUAL_continue @ yes, continue on
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_VIRTUAL_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/OP_INVOKE_SUPER.S */
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ cmp r2, #0 @ null "this"?
+ ldr r9, [rGLUE, #offGlue_method] @ r9<- current method
+ beq common_errNullObject @ null "this", throw exception
+ cmp r0, #0 @ already resolved?
+ ldr r9, [r9, #offMethod_clazz] @ r9<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_SUPER_continue @ resolved, continue on
+ b .LOP_INVOKE_SUPER_resolve @ do resolve now
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/OP_INVOKE_DIRECT.S */
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ beq .LOP_INVOKE_DIRECT_resolve @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+ cmp r2, #0 @ null "this" ref?
+ bne common_invokeMethodNoRange @ no, continue on
+ b common_errNullObject @ yes, throw exception
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/OP_INVOKE_STATIC.S */
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne common_invokeMethodNoRange @ yes, continue on
+0: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_STATIC @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne common_invokeMethodNoRange @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/OP_INVOKE_INTERFACE.S */
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r2, 2) @ r2<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!0)
+ and r2, r2, #15 @ r2<- C (or stays CCCC)
+ .endif
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r0, r2) @ r0<- first arg ("this")
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- methodClassDex
+ cmp r0, #0 @ null obj?
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- method
+ beq common_errNullObject @ yes, fail
+ ldr r0, [r0, #offObject_clazz] @ r0<- thisPtr->clazz
+ 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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/OP_UNUSED_73.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_RANGE.S */
+/* File: armv5te/OP_INVOKE_VIRTUAL.S */
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_VIRTUAL_RANGE_continue @ yes, continue on
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_VIRTUAL_RANGE_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/OP_INVOKE_SUPER_RANGE.S */
+/* File: armv5te/OP_INVOKE_SUPER.S */
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ cmp r2, #0 @ null "this"?
+ ldr r9, [rGLUE, #offGlue_method] @ r9<- current method
+ beq common_errNullObject @ null "this", throw exception
+ cmp r0, #0 @ already resolved?
+ ldr r9, [r9, #offMethod_clazz] @ r9<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_SUPER_RANGE_continue @ resolved, continue on
+ b .LOP_INVOKE_SUPER_RANGE_resolve @ do resolve now
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/OP_INVOKE_DIRECT_RANGE.S */
+/* File: armv5te/OP_INVOKE_DIRECT.S */
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ beq .LOP_INVOKE_DIRECT_RANGE_resolve @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+ cmp r2, #0 @ null "this" ref?
+ bne common_invokeMethodRange @ no, continue on
+ b common_errNullObject @ yes, throw exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/OP_INVOKE_STATIC_RANGE.S */
+/* File: armv5te/OP_INVOKE_STATIC.S */
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne common_invokeMethodRange @ yes, continue on
+0: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_STATIC @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne common_invokeMethodRange @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/OP_INVOKE_INTERFACE_RANGE.S */
+/* File: armv5te/OP_INVOKE_INTERFACE.S */
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r2, 2) @ r2<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!1)
+ and r2, r2, #15 @ r2<- C (or stays CCCC)
+ .endif
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r0, r2) @ r0<- first arg ("this")
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- methodClassDex
+ cmp r0, #0 @ null obj?
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- method
+ beq common_errNullObject @ yes, fail
+ ldr r0, [r0, #offObject_clazz] @ r0<- thisPtr->clazz
+ 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
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/OP_UNUSED_79.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/OP_UNUSED_7A.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_INT: /* 0x7b */
+/* File: armv5te/OP_NEG_INT.S */
+/* File: armv5te/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB
+ and r9, r9, #15
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ rsb r0, r0, #0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NOT_INT: /* 0x7c */
+/* File: armv5te/OP_NOT_INT.S */
+/* File: armv5te/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB
+ and r9, r9, #15
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mvn r0, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_LONG: /* 0x7d */
+/* File: armv5te/OP_NEG_LONG.S */
+/* File: armv5te/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ rsbs r0, r0, #0 @ optional op; may set condition codes
+ rsc r1, r1, #0 @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NOT_LONG: /* 0x7e */
+/* File: armv5te/OP_NOT_LONG.S */
+/* File: armv5te/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mvn r0, r0 @ optional op; may set condition codes
+ mvn r1, r1 @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv5te/OP_NEG_FLOAT.S */
+/* File: armv5te/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB
+ and r9, r9, #15
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ add r0, r0, #0x80000000 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv5te/OP_NEG_DOUBLE.S */
+/* File: armv5te/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ add r1, r1, #0x80000000 @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv5te/OP_INT_TO_LONG.S */
+/* File: armv5te/unopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0", where
+ * "result" is a 64-bit quantity in r0/r1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r0, r3) @ r0<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r1, r0, asr #31 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: arm-vfp/OP_INT_TO_FLOAT.S */
+/* File: arm-vfp/funop.S */
+ /*
+ * Generic 32-bit unary floating-point operation. Provide an "instr"
+ * line that specifies an instruction that performs "s1 = op s0".
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fsitos s1, s0 @ s1<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s1, [r9] @ vA<- s1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: arm-vfp/OP_INT_TO_DOUBLE.S */
+/* File: arm-vfp/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fsitod d0, s0 @ d0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fstd d0, [r9] @ vA<- d0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/OP_LONG_TO_INT.S */
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+/* File: armv5te/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ mov r0, rINST, lsr #8 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ and r0, r0, #15
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r2, r0) @ fp[A]<- r2
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv5te/OP_LONG_TO_FLOAT.S */
+/* File: armv5te/unopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0/r1", where
+ * "result" is a 32-bit quantity in r0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ *
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ and r9, r9, #15
+ ldmia r3, {r0-r1} @ r0/r1<- vB/vB+1
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_l2f @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv5te/OP_LONG_TO_DOUBLE.S */
+/* File: armv5te/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_l2d @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: arm-vfp/OP_FLOAT_TO_INT.S */
+/* File: arm-vfp/funop.S */
+ /*
+ * Generic 32-bit unary floating-point operation. Provide an "instr"
+ * line that specifies an instruction that performs "s1 = op s0".
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ ftosizs s1, s0 @ s1<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s1, [r9] @ vA<- s1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv5te/OP_FLOAT_TO_LONG.S */
+@include "armv5te/unopWider.S" {"instr":"bl __aeabi_f2lz"}
+/* File: armv5te/unopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0", where
+ * "result" is a 64-bit quantity in r0/r1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r0, r3) @ r0<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ bl f2l_doconv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: arm-vfp/OP_FLOAT_TO_DOUBLE.S */
+/* File: arm-vfp/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fcvtds d0, s0 @ d0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fstd d0, [r9] @ vA<- d0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: arm-vfp/OP_DOUBLE_TO_INT.S */
+/* File: arm-vfp/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary floating point operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ fldd d0, [r3] @ d0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ ftosizd s0, d0 @ s0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s0, [r9] @ vA<- s0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv5te/OP_DOUBLE_TO_LONG.S */
+@include "armv5te/unopWide.S" {"instr":"bl __aeabi_d2lz"}
+/* File: armv5te/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl d2l_doconv @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-13 instructions */
+
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: arm-vfp/OP_DOUBLE_TO_FLOAT.S */
+/* File: arm-vfp/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary floating point operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ fldd d0, [r3] @ d0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fcvtsd s0, d0 @ s0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s0, [r9] @ vA<- s0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv5te/OP_INT_TO_BYTE.S */
+/* File: armv5te/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB
+ and r9, r9, #15
+ mov r0, r0, asl #24 @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r0, r0, asr #24 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv5te/OP_INT_TO_CHAR.S */
+/* File: armv5te/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB
+ and r9, r9, #15
+ mov r0, r0, asl #16 @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r0, r0, lsr #16 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv5te/OP_INT_TO_SHORT.S */
+/* File: armv5te/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB
+ and r9, r9, #15
+ mov r0, r0, asl #16 @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r0, r0, asr #16 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/OP_ADD_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/OP_SUB_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ sub r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/OP_MUL_INT.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/OP_DIV_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT: /* 0x94 */
+/* File: armv5te/OP_REM_INT.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT: /* 0x95 */
+/* File: armv5te/OP_AND_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT: /* 0x96 */
+/* File: armv5te/OP_OR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/OP_XOR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/OP_SHL_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/OP_SHR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/OP_USHR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/OP_ADD_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ adds r0, r0, r2 @ optional op; may set condition codes
+ adc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/OP_SUB_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ subs r0, r0, r2 @ optional op; may set condition codes
+ sbc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/OP_MUL_LONG.S */
+ /*
+ * Signed 64-bit integer multiply.
+ *
+ * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
+ * WX
+ * x YZ
+ * --------
+ * ZW ZX
+ * YW YX
+ *
+ * The low word of the result holds ZX, the high word holds
+ * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
+ * it doesn't fit in the low 64 bits.
+ *
+ * Unlike most ARM math operations, multiply instructions have
+ * restrictions on using the same register more than once (Rd and Rm
+ * cannot be the same).
+ */
+ /* mul-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ mov r0, rINST, lsr #8 @ r0<- AA
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ add r0, rFP, r0, lsl #2 @ r0<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_MUL_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/OP_DIV_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/OP_REM_LONG.S */
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r2,r3} @ vAA/vAA+1<- r2/r3
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/OP_AND_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r0, r0, r2 @ optional op; may set condition codes
+ and r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/OP_OR_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ orr r0, r0, r2 @ optional op; may set condition codes
+ orr r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/OP_XOR_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ eor r0, r0, r2 @ optional op; may set condition codes
+ eor r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/OP_SHL_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shl-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r3, r0, #255 @ r3<- BB
+ mov r0, r0, lsr #8 @ r0<- CC
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
+ GET_VREG(r2, r0) @ r2<- vCC
+ ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_SHL_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/OP_SHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shr-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r3, r0, #255 @ r3<- BB
+ mov r0, r0, lsr #8 @ r0<- CC
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
+ GET_VREG(r2, r0) @ r2<- vCC
+ ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_SHR_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/OP_USHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* ushr-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r3, r0, #255 @ r3<- BB
+ mov r0, r0, lsr #8 @ r0<- CC
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
+ GET_VREG(r2, r0) @ r2<- vCC
+ ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_USHR_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_FLOAT: /* 0xa6 */
+/* File: arm-vfp/OP_ADD_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fadds s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_FLOAT: /* 0xa7 */
+/* File: arm-vfp/OP_SUB_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fsubs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_FLOAT: /* 0xa8 */
+/* File: arm-vfp/OP_MUL_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fmuls s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_FLOAT: /* 0xa9 */
+/* File: arm-vfp/OP_DIV_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fdivs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/OP_REM_FLOAT.S */
+/* EABI doesn't define a float remainder function, but libm does */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl fmodf @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_DOUBLE: /* 0xab */
+/* File: arm-vfp/OP_ADD_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ faddd d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_DOUBLE: /* 0xac */
+/* File: arm-vfp/OP_SUB_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fsubd d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_DOUBLE: /* 0xad */
+/* File: arm-vfp/OP_MUL_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fmuld d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_DOUBLE: /* 0xae */
+/* File: arm-vfp/OP_DIV_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fdivd d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/OP_REM_DOUBLE.S */
+/* EABI doesn't define a double remainder function, but libm does */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl fmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv5te/OP_ADD_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv5te/OP_SUB_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ sub r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv5te/OP_MUL_INT_2ADDR.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv5te/OP_DIV_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv5te/OP_REM_INT_2ADDR.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv5te/OP_AND_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv5te/OP_OR_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv5te/OP_XOR_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv5te/OP_SHL_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv5te/OP_SHR_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv5te/OP_USHR_INT_2ADDR.S */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv5te/OP_ADD_LONG_2ADDR.S */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ adds r0, r0, r2 @ optional op; may set condition codes
+ adc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv5te/OP_SUB_LONG_2ADDR.S */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ subs r0, r0, r2 @ optional op; may set condition codes
+ sbc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv5te/OP_MUL_LONG_2ADDR.S */
+ /*
+ * Signed 64-bit integer multiply, "/2addr" version.
+ *
+ * See OP_MUL_LONG for an explanation.
+ *
+ * We get a little tight on registers, so to avoid looking up &fp[A]
+ * again we stuff it into rINST.
+ */
+ /* mul-long/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add rINST, rFP, r9, lsl #2 @ rINST<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia rINST, {r0-r1} @ r0/r1<- vAA/vAA+1
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ mov r0, rINST @ r0<- &fp[A] (free up rINST)
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv5te/OP_DIV_LONG_2ADDR.S */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv5te/OP_REM_LONG_2ADDR.S */
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r2,r3} @ vAA/vAA+1<- r2/r3
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv5te/OP_AND_LONG_2ADDR.S */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r0, r0, r2 @ optional op; may set condition codes
+ and r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv5te/OP_OR_LONG_2ADDR.S */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ orr r0, r0, r2 @ optional op; may set condition codes
+ orr r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv5te/OP_XOR_LONG_2ADDR.S */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ eor r0, r0, r2 @ optional op; may set condition codes
+ eor r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv5te/OP_SHL_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shl-long/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ b .LOP_SHL_LONG_2ADDR_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv5te/OP_SHR_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shr-long/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
+ mov r1, r1, asr r2 @ r1<- r1 >> r2
+ b .LOP_SHR_LONG_2ADDR_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv5te/OP_USHR_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* ushr-long/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
+ mov r1, r1, lsr r2 @ r1<- r1 >>> r2
+ b .LOP_USHR_LONG_2ADDR_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: arm-vfp/OP_ADD_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fadds s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: arm-vfp/OP_SUB_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fsubs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: arm-vfp/OP_MUL_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fmuls s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: arm-vfp/OP_DIV_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fdivs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv5te/OP_REM_FLOAT_2ADDR.S */
+/* EABI doesn't define a float remainder function, but libm does */
+/* File: armv5te/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r3, rINST, lsr #12 @ r3<- B
+ and r9, r9, #15
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl fmodf @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: arm-vfp/OP_ADD_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ faddd d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: arm-vfp/OP_SUB_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ fsubd d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: arm-vfp/OP_MUL_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ fmuld d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: arm-vfp/OP_DIV_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ fdivd d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv5te/OP_REM_DOUBLE_2ADDR.S */
+/* EABI doesn't define a double remainder function, but libm does */
+/* File: armv5te/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r9, rINST, lsr #8 @ r9<- A+
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r9, r9, #15
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl fmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv5te/OP_ADD_INT_LIT16.S */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RSUB_INT: /* 0xd1 */
+/* File: armv5te/OP_RSUB_INT.S */
+/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ rsb r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv5te/OP_MUL_INT_LIT16.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv5te/OP_DIV_INT_LIT16.S */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv5te/OP_REM_INT_LIT16.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv5te/OP_AND_INT_LIT16.S */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv5te/OP_OR_INT_LIT16.S */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv5te/OP_XOR_INT_LIT16.S */
+/* File: armv5te/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r2) @ r0<- vB
+ and r9, r9, #15
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/OP_ADD_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/OP_RSUB_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ rsb r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/OP_MUL_INT_LIT8.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/OP_DIV_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 1
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/OP_REM_INT_LIT8.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 1
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/OP_AND_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/OP_OR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/OP_XOR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/OP_SHL_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/OP_SHR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/OP_USHR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E3: /* 0xe3 */
+/* File: armv5te/OP_UNUSED_E3.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E4: /* 0xe4 */
+/* File: armv5te/OP_UNUSED_E4.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E5: /* 0xe5 */
+/* File: armv5te/OP_UNUSED_E5.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E6: /* 0xe6 */
+/* File: armv5te/OP_UNUSED_E6.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E7: /* 0xe7 */
+/* File: armv5te/OP_UNUSED_E7.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E8: /* 0xe8 */
+/* File: armv5te/OP_UNUSED_E8.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E9: /* 0xe9 */
+/* File: armv5te/OP_UNUSED_E9.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EA: /* 0xea */
+/* File: armv5te/OP_UNUSED_EA.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EB: /* 0xeb */
+/* File: armv5te/OP_UNUSED_EB.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EC: /* 0xec */
+/* File: armv5te/OP_UNUSED_EC.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR.S */
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ FETCH(r2, 1) @ r2<- BBBB
+ EXPORT_PC() @ export the PC
+ mov r1, rINST, lsr #8 @ r1<- AA
+ bl dvmThrowVerificationError @ always throws
+ b common_exceptionThrown @ handle exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/OP_EXECUTE_INLINE.S */
+ /*
+ * Execute a "native inline" instruction.
+ *
+ * We need to call:
+ * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)
+ *
+ * The first four args are in r0-r3, but the last two must be pushed
+ * onto the stack.
+ */
+ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+ FETCH(r10, 1) @ r10<- BBBB
+ add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval
+ EXPORT_PC() @ can throw
+ sub sp, sp, #8 @ make room for arg(s)
+ mov r0, rINST, lsr #12 @ r0<- B
+ str r1, [sp] @ push &glue->retval
+ bl .LOP_EXECUTE_INLINE_continue @ make call; will return after
+ add sp, sp, #8 @ pop stack
+ cmp r0, #0 @ test boolean result of inline
+ beq common_exceptionThrown @ returned false, handle exception
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EF: /* 0xef */
+/* File: armv5te/OP_UNUSED_EF.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_DIRECT_EMPTY: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_DIRECT_EMPTY.S */
+ /*
+ * invoke-direct-empty is a no-op in a "standard" interpreter.
+ */
+ FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_F1: /* 0xf1 */
+/* File: armv5te/OP_UNUSED_F1.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv5te/OP_IGET_QUICK.S */
+ /* For: iget-quick, iget-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ GET_VREG(r3, r2) @ r3<- object we're operating on
+ 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
+ ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_WIDE_QUICK: /* 0xf3 */
+/* File: armv5te/OP_IGET_WIDE_QUICK.S */
+ /* iget-wide-quick vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ GET_VREG(r3, r2) @ r3<- object we're operating on
+ 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
+ ldrd r0, [r3, r1] @ r0<- obj.field (64 bits, aligned)
+ and r2, r2, #15
+ 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 */
+/* File: armv5te/OP_IGET_OBJECT_QUICK.S */
+/* File: armv5te/OP_IGET_QUICK.S */
+ /* For: iget-quick, iget-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ GET_VREG(r3, r2) @ r3<- object we're operating on
+ 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
+ ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ 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 */
+ /* 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]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv5te/OP_IPUT_WIDE_QUICK.S */
+ /* iput-wide-quick vA, vB, offset@CCCC */
+ mov r0, rINST, lsr #8 @ r0<- A(+)
+ mov r1, rINST, lsr #12 @ r1<- B
+ and r0, r0, #15
+ GET_VREG(r2, r1) @ r2<- fp[B], the object pointer
+ add r3, rFP, r0, lsl #2 @ r3<- &fp[A]
+ cmp r2, #0 @ check object for null
+ ldmia r3, {r0-r1} @ r0/r1<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH(r3, 1) @ r3<- field byte offset
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
+
+
+/* ------------------------------ */
+ .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 */
+ /* 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]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r3, 2) @ r3<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!0)
+ and r3, r3, #15 @ r3<- C (or stays CCCC)
+ .endif
+ GET_VREG(r2, r3) @ r2<- vC ("this" ptr)
+ cmp r2, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r2, [r2, #offObject_clazz] @ r2<- thisPtr->clazz
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- thisPtr->clazz->vtable
+ EXPORT_PC() @ invoke must export
+ ldr r0, [r2, r1, lsl #2] @ r3<- vtable[BBBB]
+ bl common_invokeMethodNoRange @ continue on
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r3, 2) @ r3<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!1)
+ and r3, r3, #15 @ r3<- C (or stays CCCC)
+ .endif
+ GET_VREG(r2, r3) @ r2<- vC ("this" ptr)
+ cmp r2, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r2, [r2, #offObject_clazz] @ r2<- thisPtr->clazz
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- thisPtr->clazz->vtable
+ EXPORT_PC() @ invoke must export
+ ldr r0, [r2, r1, lsl #2] @ r3<- vtable[BBBB]
+ bl common_invokeMethodRange @ continue on
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [r2, #offMethod_clazz] @ r2<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ ldr r2, [r2, #offClassObject_super] @ r2<- method->clazz->super
+ GET_VREG(r3, r10) @ r3<- "this"
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- ...clazz->super->vtable
+ cmp r3, #0 @ null "this" ref?
+ ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
+ beq common_errNullObject @ "this" is null, throw exception
+ bl common_invokeMethodNoRange @ continue on
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [r2, #offMethod_clazz] @ r2<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ ldr r2, [r2, #offClassObject_super] @ r2<- method->clazz->super
+ GET_VREG(r3, r10) @ r3<- "this"
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- ...clazz->super->vtable
+ cmp r3, #0 @ null "this" ref?
+ ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
+ beq common_errNullObject @ "this" is null, throw exception
+ 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
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_FD: /* 0xfd */
+/* File: armv5te/OP_UNUSED_FD.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_FE: /* 0xfe */
+/* File: armv5te/OP_UNUSED_FE.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_FF: /* 0xff */
+/* File: armv5te/OP_UNUSED_FF.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+
+ .balign 64
+ .size dvmAsmInstructionStart, .-dvmAsmInstructionStart
+ .global dvmAsmInstructionEnd
+dvmAsmInstructionEnd:
+
+/*
+ * ===========================================================================
+ * Sister implementations
+ * ===========================================================================
+ */
+ .global dvmAsmSisterStart
+ .type dvmAsmSisterStart, %function
+ .text
+ .balign 4
+dvmAsmSisterStart:
+
+/* continuation for OP_CONST_STRING */
+
+ /*
+ * Continuation if the String has not yet been resolved.
+ * r1: BBBB (String ref)
+ * r9: target register
+ */
+.LOP_CONST_STRING_resolve:
+ EXPORT_PC()
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveString @ r0<- String reference
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yup, handle the exception
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_CONST_STRING_JUMBO */
+
+ /*
+ * Continuation if the String has not yet been resolved.
+ * r1: BBBBBBBB (String ref)
+ * r9: target register
+ */
+.LOP_CONST_STRING_JUMBO_resolve:
+ EXPORT_PC()
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveString @ r0<- String reference
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yup, handle the exception
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_CONST_CLASS */
+
+ /*
+ * Continuation if the Class has not yet been resolved.
+ * r1: BBBB (Class ref)
+ * r9: target register
+ */
+.LOP_CONST_CLASS_resolve:
+ EXPORT_PC()
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ mov r2, #1 @ r2<- true
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- Class reference
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yup, handle the exception
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_CHECK_CAST */
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * r0 holds obj->clazz
+ * r1 holds class resolved from BBBB
+ * r9 holds object
+ */
+.LOP_CHECK_CAST_fullcheck:
+ bl dvmInstanceofNonTrivial @ r0<- boolean result
+ cmp r0, #0 @ failed?
+ bne .LOP_CHECK_CAST_okay @ no, success
+
+ @ A cast has failed. We need to throw a ClassCastException with the
+ @ class of the object that failed to be cast.
+ EXPORT_PC() @ about to throw
+ ldr r3, [r9, #offObject_clazz] @ r3<- obj->clazz
+ ldr r0, .LstrClassCastExceptionPtr
+ ldr r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
+ bl dvmThrowExceptionWithClassMessage
+ b common_exceptionThrown
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * r2 holds BBBB
+ * r9 holds object
+ */
+.LOP_CHECK_CAST_resolve:
+ EXPORT_PC() @ resolve() could throw
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r1, r2 @ r1<- BBBB
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- resolved ClassObject ptr
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ mov r1, r0 @ r1<- class resolved from BBB
+ ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
+ b .LOP_CHECK_CAST_resolved @ pick up where we left off
+
+.LstrClassCastExceptionPtr:
+ .word .LstrClassCastException
+
+
+/* continuation for OP_INSTANCE_OF */
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * r0 holds obj->clazz
+ * r1 holds class resolved from BBBB
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_fullcheck:
+ bl dvmInstanceofNonTrivial @ r0<- boolean result
+ @ fall through to OP_INSTANCE_OF_store
+
+ /*
+ * r0 holds boolean result
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_store:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+ /*
+ * Trivial test succeeded, save and bail.
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_trivial:
+ mov r0, #1 @ indicate success
+ @ could b OP_INSTANCE_OF_store, but copying is faster and cheaper
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * r3 holds BBBB
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_resolve:
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ mov r1, r3 @ r1<- BBBB
+ mov r2, #1 @ r2<- true
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- resolved ClassObject ptr
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ mov r1, r0 @ r1<- class resolved from BBB
+ mov r3, rINST, lsr #12 @ r3<- B
+ GET_VREG(r0, r3) @ r0<- vB (object)
+ 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
+.LOP_NEW_INSTANCE_finish: @ r0=new object
+ mov r3, rINST, lsr #8 @ r3<- AA
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yes, handle the exception
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+ /*
+ * Class initialization required.
+ *
+ * r0 holds class object
+ */
+.LOP_NEW_INSTANCE_needinit:
+ mov r9, r0 @ save r0
+ bl dvmInitClass @ initialize class
+ cmp r0, #0 @ check boolean result
+ mov r0, r9 @ restore r0
+ bne .LOP_NEW_INSTANCE_initialized @ success, continue
+ b common_exceptionThrown @ failed, deal with init exception
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * r1 holds BBBB
+ */
+.LOP_NEW_INSTANCE_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- resolved ClassObject ptr
+ cmp r0, #0 @ got null?
+ bne .LOP_NEW_INSTANCE_resolved @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+.LstrInstantiationErrorPtr:
+ .word .LstrInstantiationError
+
+
+/* continuation for OP_NEW_ARRAY */
+
+
+ /*
+ * Resolve class. (This is an uncommon case.)
+ *
+ * r1 holds array length
+ * r2 holds class ref CCCC
+ */
+.LOP_NEW_ARRAY_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r9, r1 @ r9<- length (save)
+ mov r1, r2 @ r1<- CCCC
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- call(clazz, ref)
+ cmp r0, #0 @ got null?
+ mov r1, r9 @ r1<- length (restore)
+ beq common_exceptionThrown @ yes, handle exception
+ @ fall through to OP_NEW_ARRAY_finish
+
+ /*
+ * Finish allocation.
+ *
+ * r0 holds class
+ * r1 holds array length
+ */
+.LOP_NEW_ARRAY_finish:
+ mov r2, #ALLOC_DONT_TRACK @ don't track in local refs table
+ bl dvmAllocArrayByClass @ r0<- call(clazz, length, flags)
+ cmp r0, #0 @ failed?
+ mov r2, rINST, lsr #8 @ r2<- A+
+ beq common_exceptionThrown @ yes, handle the exception
+ 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) @ vA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_FILLED_NEW_ARRAY */
+
+ /*
+ * On entry:
+ * r0 holds array class
+ * r10 holds AA or BA
+ */
+.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]
+ .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?
+ mov r9, r1 @ save length in r9
+ bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
+ bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
+ cmp r0, #0 @ null return?
+ beq common_exceptionThrown @ alloc failed, handle exception
+
+ FETCH(r1, 2) @ r1<- FEDC or CCCC
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ 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
+ bmi 2f @ was zero, bail
+
+ @ copy values from registers into the array
+ @ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
+ .if 0
+ add r2, rFP, r1, lsl #2 @ r2<- &fp[CCCC]
+1: ldr r3, [r2], #4 @ r3<- *r2++
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .else
+ cmp r9, #4 @ length was initially 5?
+ and r2, r10, #15 @ r2<- A
+ bne 1f @ <= 4 args, branch
+ GET_VREG(r3, r2) @ r3<- vA
+ sub r9, r9, #1 @ count--
+ str r3, [r0, #16] @ contents[4] = vA
+1: and r2, r1, #15 @ r2<- F/E/D/C
+ GET_VREG(r3, r2) @ r3<- vF/vE/vD/vC
+ mov r1, r1, lsr #4 @ r1<- next reg in low 4
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .endif
+
+2:
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.LOP_FILLED_NEW_ARRAY_notimpl:
+ ldr r0, .L_strInternalError
+ ldr r1, .L_strFilledNewArrayNotImpl
+ bl dvmThrowException
+ b common_exceptionThrown
+
+ .if (!0) @ define in one or the other, not both
+.L_strFilledNewArrayNotImpl:
+ .word .LstrFilledNewArrayNotImpl
+.L_strInternalError:
+ .word .LstrInternalError
+ .endif
+
+
+/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
+
+ /*
+ * On entry:
+ * r0 holds array class
+ * r10 holds AA or BA
+ */
+.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]
+ .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?
+ 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)
+ cmp r0, #0 @ null return?
+ beq common_exceptionThrown @ alloc failed, handle exception
+
+ FETCH(r1, 2) @ r1<- FEDC or CCCC
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ 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
+ bmi 2f @ was zero, bail
+
+ @ copy values from registers into the array
+ @ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
+ .if 1
+ add r2, rFP, r1, lsl #2 @ r2<- &fp[CCCC]
+1: ldr r3, [r2], #4 @ r3<- *r2++
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .else
+ cmp r9, #4 @ length was initially 5?
+ and r2, r10, #15 @ r2<- A
+ bne 1f @ <= 4 args, branch
+ GET_VREG(r3, r2) @ r3<- vA
+ sub r9, r9, #1 @ count--
+ str r3, [r0, #16] @ contents[4] = vA
+1: and r2, r1, #15 @ r2<- F/E/D/C
+ GET_VREG(r3, r2) @ r3<- vF/vE/vD/vC
+ mov r1, r1, lsr #4 @ r1<- next reg in low 4
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .endif
+
+2:
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
+ ldr r0, .L_strInternalError
+ ldr r1, .L_strFilledNewArrayNotImpl
+ bl dvmThrowException
+ b common_exceptionThrown
+
+ .if (!1) @ define in one or the other, not both
+.L_strFilledNewArrayNotImpl:
+ .word .LstrFilledNewArrayNotImpl
+.L_strInternalError:
+ .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:
+ mvn r1, #0 @ r1<- -1
+ @ Want to cond code the next mov so we can avoid branch, but don't see it;
+ @ instead, we just replicate the tail end.
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+.LOP_CMP_LONG_greater:
+ mov r1, #1 @ r1<- 1
+ @ fall through to _finish
+
+.LOP_CMP_LONG_finish:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_AGET_WIDE */
+
+.LOP_AGET_WIDE_finish:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ 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, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_APUT_OBJECT */
+ /*
+ * On entry:
+ * r1 = vBB (arrayObj)
+ * r9 = vAA (obj)
+ * r10 = offset into array (vBB + vCC * width)
+ */
+.LOP_APUT_OBJECT_finish:
+ cmp r9, #0 @ storing null reference?
+ beq .LOP_APUT_OBJECT_skip_check @ yes, skip type checks
+ ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
+ ldr r1, [r1, #offObject_clazz] @ r1<- arrayObj->clazz
+ bl dvmCanPutArrayElement @ test object type vs. array type
+ cmp r0, #0 @ okay?
+ beq common_errArrayStore @ no
+.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 */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_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)
+ 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 */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_finish:
+ 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+
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ and r2, r2, #15 @ r2<- A
+ 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
+
+
+/* continuation for OP_IGET_OBJECT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_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)
+ 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_BOOLEAN */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_BOOLEAN_finish:
+ @bl common_squeak1
+ 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)
+ 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_BYTE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_BYTE_finish:
+ @bl common_squeak2
+ 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)
+ 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_CHAR */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_CHAR_finish:
+ @bl common_squeak3
+ 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)
+ 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_SHORT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_SHORT_finish:
+ @bl common_squeak4
+ 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)
+ 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 */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_WIDE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_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(ip) @ extract opcode from rINST
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_OBJECT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_BOOLEAN_finish:
+ @bl common_squeak1
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_BYTE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_BYTE_finish:
+ @bl common_squeak2
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_CHAR */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_CHAR_finish:
+ @bl common_squeak3
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_SHORT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_SHORT_finish:
+ @bl common_squeak4
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_SGET */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_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_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
+ */
+.LOP_SGET_WIDE_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_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_OBJECT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_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_SGET_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_BOOLEAN */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_BOOLEAN_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_BOOLEAN_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_BYTE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_BYTE_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_BYTE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_CHAR */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_CHAR_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_CHAR_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_SHORT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_SHORT_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_SHORT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_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_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]
+ */
+.LOP_SPUT_WIDE_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_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
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_BOOLEAN_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_BOOLEAN_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT_BYTE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_BYTE_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_BYTE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT_CHAR */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_CHAR_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_CHAR_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT_SHORT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_SHORT_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_SHORT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_INVOKE_VIRTUAL */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r10 = C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.LOP_INVOKE_VIRTUAL_continue:
+ GET_VREG(r1, r10) @ r1<- "this" ptr
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ cmp r1, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r3, [r1, #offObject_clazz] @ r1<- thisPtr->clazz
+ ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
+ ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodNoRange @ continue on
+
+
+/* continuation for OP_INVOKE_SUPER */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r9 = method->clazz
+ */
+.LOP_INVOKE_SUPER_continue:
+ ldr r1, [r9, #offClassObject_super] @ r1<- method->clazz->super
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ ldr r3, [r1, #offClassObject_vtableCount] @ r3<- super->vtableCount
+ EXPORT_PC() @ must export for invoke
+ cmp r2, r3 @ compare (methodIndex, vtableCount)
+ bcs .LOP_INVOKE_SUPER_nsm @ method not present in superclass
+ ldr r1, [r1, #offClassObject_vtable] @ r1<- ...clazz->super->vtable
+ ldr r0, [r1, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodNoRange @ continue on
+
+.LOP_INVOKE_SUPER_resolve:
+ mov r0, r9 @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_SUPER_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * r0 = resolved base method
+ */
+.LOP_INVOKE_SUPER_nsm:
+ ldr r1, [r0, #offMethod_name] @ r1<- method name
+ b common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_DIRECT */
+
+ /*
+ * On entry:
+ * r1 = reference (BBBB or CCCC)
+ * r10 = "this" register
+ */
+.LOP_INVOKE_DIRECT_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_DIRECT @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
+ bne .LOP_INVOKE_DIRECT_finish @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+/* continuation for OP_INVOKE_VIRTUAL_RANGE */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r10 = C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.LOP_INVOKE_VIRTUAL_RANGE_continue:
+ GET_VREG(r1, r10) @ r1<- "this" ptr
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ cmp r1, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r3, [r1, #offObject_clazz] @ r1<- thisPtr->clazz
+ ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
+ ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodRange @ continue on
+
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r9 = method->clazz
+ */
+.LOP_INVOKE_SUPER_RANGE_continue:
+ ldr r1, [r9, #offClassObject_super] @ r1<- method->clazz->super
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ ldr r3, [r1, #offClassObject_vtableCount] @ r3<- super->vtableCount
+ EXPORT_PC() @ must export for invoke
+ cmp r2, r3 @ compare (methodIndex, vtableCount)
+ bcs .LOP_INVOKE_SUPER_RANGE_nsm @ method not present in superclass
+ ldr r1, [r1, #offClassObject_vtable] @ r1<- ...clazz->super->vtable
+ ldr r0, [r1, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodRange @ continue on
+
+.LOP_INVOKE_SUPER_RANGE_resolve:
+ mov r0, r9 @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_SUPER_RANGE_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * r0 = resolved base method
+ */
+.LOP_INVOKE_SUPER_RANGE_nsm:
+ ldr r1, [r0, #offMethod_name] @ r1<- method name
+ b common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_DIRECT_RANGE */
+
+ /*
+ * On entry:
+ * r1 = reference (BBBB or CCCC)
+ * r10 = "this" register
+ */
+.LOP_INVOKE_DIRECT_RANGE_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_DIRECT @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
+ 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.
+ *
+ * We have to clip values to long min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+f2l_doconv:
+ stmfd sp!, {r4, lr}
+ mov r1, #0x5f000000 @ (float)maxlong
+ mov r4, r0
+ bl __aeabi_fcmpge @ is arg >= maxlong?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0 @ return maxlong (7fffffff)
+ mvnne r1, #0x80000000
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, #0xdf000000 @ (float)minlong
+ bl __aeabi_fcmple @ is arg <= minlong?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0 @ return minlong (80000000)
+ movne r1, #0x80000000
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, r4
+ bl __aeabi_fcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ moveq r1, #0 @ return zero for NaN
+ ldmeqfd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ 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.
+ *
+ * We have to clip values to long min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+d2l_doconv:
+ stmfd sp!, {r4, r5, lr} @ save regs
+ mov r3, #0x43000000 @ maxlong, as a double (high word)
+ add r3, #0x00e00000 @ 0x43e00000
+ mov r2, #0 @ maxlong, as a double (low word)
+ sub sp, sp, #4 @ align for EABI
+ mov r4, r0 @ save a copy of r0
+ mov r5, r1 @ and r1
+ bl __aeabi_dcmpge @ is arg >= maxlong?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0 @ return maxlong (7fffffffffffffff)
+ mvnne r1, #0x80000000
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r3, #0xc3000000 @ minlong, as a double (high word)
+ add r3, #0x00e00000 @ 0xc3e00000
+ mov r2, #0 @ minlong, as a double (low word)
+ bl __aeabi_dcmple @ is arg <= minlong?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0 @ return minlong (8000000000000000)
+ movne r1, #0x80000000
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r2, r4 @ compare against self
+ mov r3, r5
+ bl __aeabi_dcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ moveq r1, #0 @ return zero for NaN
+ beq 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ bl __aeabi_d2lz @ convert double to long
+
+1:
+ add sp, sp, #4
+ ldmfd sp!, {r4, r5, pc}
+
+
+/* continuation for OP_MUL_LONG */
+
+.LOP_MUL_LONG_finish:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ mov r1, r1, asr r2 @ r1<- r1 >> r2
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ mov r1, r1, lsr r2 @ r1<- r1 >>> r2
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_EXECUTE_INLINE */
+
+ /*
+ * Extract args, call function.
+ * r0 = #of args (0-4)
+ * r10 = call index
+ * lr = return addr, above [DO NOT bl out of here w/o preserving LR]
+ *
+ * Other ideas:
+ * - Use a jump table from the main piece to jump directly into the
+ * AND/LDR pairs. Costs a data load, saves a branch.
+ * - Have five separate pieces that do the loading, so we can work the
+ * interleave a little better. Increases code size.
+ */
+.LOP_EXECUTE_INLINE_continue:
+ rsb r0, r0, #4 @ r0<- 4-r0
+ FETCH(r9, 2) @ r9<- FEDC
+ add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each
+ bl common_abort @ (skipped due to ARM prefetch)
+4: and ip, r9, #0xf000 @ isolate F
+ ldr r3, [rFP, ip, lsr #10] @ r3<- vF (shift right 12, left 2)
+3: and ip, r9, #0x0f00 @ isolate E
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vE
+2: and ip, r9, #0x00f0 @ isolate D
+ ldr r1, [rFP, ip, lsr #2] @ r1<- vD
+1: and ip, r9, #0x000f @ isolate C
+ ldr r0, [rFP, ip, lsl #2] @ r0<- vC
+0:
+ ldr r9, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
+ LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry
+ @ (not reached)
+
+.LOP_EXECUTE_INLINE_table:
+ .word gDvmInlineOpsTable
+
+
+ .size dvmAsmSisterStart, .-dvmAsmSisterStart
+ .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+/* File: armv5te/footer.S */
+
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+
+
+ .text
+ .align 2
+
+#if defined(WITH_JIT)
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ mov rPC, r0
+#ifdef EXIT_STATS
+ mov r0,lr
+ bl dvmBumpPunt;
+#endif
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * r0 <= PC
+ * r1 <= PC of resume instruction
+ * lr <= resume point in translation
+ */
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ str lr,[rGLUE,#offGlue_jitResume]
+ str r1,[rGLUE,#offGlue_jitResumePC]
+ mov r1,#kInterpEntryInstr
+ @ enum is 4 byte in aapcs-EABI
+ str r1, [rGLUE, #offGlue_entryPoint]
+ mov rPC,r0
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ mov r2,#kJitSingleStep @ Ask for single step and then revert
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp to bail to debug interp
+ b common_gotoBail
+
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToTraceSelect
+dvmJitToTraceSelect:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq 2f
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/* No translation, so request one if profiling isn't disabled*/
+2:
+ adrl rIBASE, dvmAsmInstructionStart
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0, #0
+ bne common_selectTrace
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+#ifdef EXIT_STATS
+ bl dvmBumpNormal
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq toInterpreter @ go if not, otherwise do chain
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/*
+ * 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 EXIT_STATS
+ bl dvmBumpNoChain
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rGLUE & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+toInterpreter:
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ 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
+ * next instruction to execute, and rINST should be already loaded with
+ * the next opcode word, and r0 holds a pointer to the jit profile
+ * table (pJitProfTable).
+ */
+common_testUpdateProfile:
+ cmp r0,#0
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */
+
+common_updateProfile:
+ eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
+ GET_INST_OPCODE(ip)
+ subs r1,r1,#1 @ decrement counter
+ strb r1,[r0,r3,lsr #23] @ and store it
+ GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
+
+/*
+ * Here, we switch to the debug interpreter to request
+ * trace selection. First, though, check to see if there
+ * is already a native translation in place (and, if so,
+ * jump to it now).
+ */
+ mov r1,#255
+ strb r1,[r0,r3,lsr #23] @ reset counter
+ EXPORT_PC()
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
+ cmp r0,#0
+ beq common_selectTrace
+ bxne r0 @ jump to the translation
+common_selectTrace:
+ mov r2,#kJitTSelectRequest @ ask for trace selection
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp
+ b common_gotoBail
+
+#endif
+
+/*
+ * Common code when a backward branch is taken.
+ *
+ * On entry:
+ * r9 is PC adjustment *in bytes*
+ */
+common_backwardBranch:
+ mov r0, #kInterpEntryInstr
+ bl common_periodicChecks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+/*
+ * Need to see if the thread needs to be suspended or debugger/profiler
+ * activity has begun.
+ *
+ * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
+ * have to do the second ldr.
+ *
+ * TODO: reduce this so we're just checking a single location.
+ *
+ * On entry:
+ * r0 is reentry type, e.g. kInterpEntryInstr
+ * r9 is trampoline PC adjustment *in bytes*
+ */
+common_periodicChecks:
+ ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
+
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+#endif
+
+ ldr r3, [r3] @ r3<- suspendCount (int)
+
+#if defined(WITH_DEBUGGER)
+ ldrb r1, [r1] @ r1<- debuggerActive (boolean)
+#endif
+#if defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#endif
+
+ cmp r3, #0 @ suspend pending?
+ bne 2f @ yes, do full suspension check
+
+#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
+#endif
+
+ bx lr @ nothing to do, return
+
+2: @ check suspend
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ need for precise GC
+ b dvmCheckSuspendPending @ suspend if necessary, then return
+
+3: @ debugger/profiler enabled, bail out
+ add rPC, rPC, r9 @ update rPC
+ str r0, [rGLUE, #offGlue_entryPoint]
+ mov r1, #1 @ "want switch" = true
+ b common_gotoBail
+
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ *
+ * State registers will be saved to the "glue" area before bailing.
+ *
+ * On entry:
+ * r1 is "bool changeInterp", indicating if we want to switch to the
+ * other interpreter or just bail all the way out
+ */
+common_gotoBail:
+ SAVE_PC_FP_TO_GLUE() @ export state to "glue"
+ mov r0, rGLUE @ r0<- glue ptr
+ b dvmMterpStdBail @ call(glue, changeInterp)
+
+ @add r1, r1, #1 @ using (boolean+1)
+ @add r0, rGLUE, #offGlue_jmpBuf @ r0<- &glue->jmpBuf
+ @bl _longjmp @ does not return
+ @bl common_abort
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+ @ prepare to copy args to "outs" area of current frame
+ movs r2, rINST, lsr #8 @ r2<- AA (arg count) -- test for zero
+ SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
+ beq .LinvokeArgsDone @ if no args, skip the rest
+ FETCH(r1, 2) @ r1<- CCCC
+
+ @ r0=methodToCall, r1=CCCC, r2=count, r10=outs
+ @ (very few methods have > 10 args; could unroll for common cases)
+ add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC]
+ sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+1: ldr r1, [r3], #4 @ val = *fp++
+ subs r2, r2, #1 @ count--
+ str r1, [r10], #4 @ *outs++ = val
+ bne 1b @ ...while count != 0
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ b .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ @ prepare to copy args to "outs" area of current frame
+ movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero
+ SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
+ FETCH(r1, 2) @ r1<- GFED (load here to hide latency)
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ beq .LinvokeArgsDone
+
+ @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
+.LinvokeNonRange:
+ rsb r2, r2, #5 @ r2<- 5-r2
+ add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each
+ bl common_abort @ (skipped due to ARM prefetch)
+5: and ip, rINST, #0x0f00 @ isolate A
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2)
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vA
+4: and ip, r1, #0xf000 @ isolate G
+ ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2)
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vG
+3: and ip, r1, #0x0f00 @ isolate F
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vF
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vF
+2: and ip, r1, #0x00f0 @ isolate E
+ ldr r2, [rFP, ip, lsr #2] @ r2<- vE
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vE
+1: and ip, r1, #0x000f @ isolate D
+ ldr r2, [rFP, ip, lsl #2] @ r2<- vD
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vD
+0: @ fall through to .LinvokeArgsDone
+
+.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
+ ldr r2, [r0, #offMethod_insns] @ r2<- method->insns
+ ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz
+ @ find space for the new stack frame, check for overflow
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
+ sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea
+@ bl common_dumpRegs
+ ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
+ 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
+
+ @ set up newSaveArea
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(ip, rFP) @ ip<- stack save area
+ str ip, [r10, #offStackSaveArea_prevSave]
+#endif
+ str rFP, [r10, #offStackSaveArea_prevFrame]
+ str rPC, [r10, #offStackSaveArea_savedPc]
+#if defined(WITH_JIT)
+ mov r9, #0
+ str r9, [r10, #offStackSaveArea_returnAddr]
+#endif
+ str r0, [r10, #offStackSaveArea_method]
+ tst r3, #ACC_NATIVE
+ bne .LinvokeNative
+
+ /*
+ stmfd sp!, {r0-r3}
+ bl common_printNewline
+ mov r0, rFP
+ mov r1, #0
+ bl dvmDumpFp
+ ldmfd sp!, {r0-r3}
+ stmfd sp!, {r0-r3}
+ mov r0, r1
+ mov r1, r10
+ bl dvmDumpFp
+ bl common_printNewline
+ ldmfd sp!, {r0-r3}
+ */
+
+ ldrh r9, [r2] @ r9 <- load INST from new PC
+ ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ mov rPC, r2 @ publish new rPC
+ ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
+
+ @ Update "glue" values for the new method
+ @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ cmp r0,#0
+ bne common_updateProfile
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+.LinvokeNative:
+ @ Prep for the native call
+ @ r0=methodToCall, r1=newFp, r10=newSaveArea
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ ldr r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+ str r1, [r3, #offThread_curFrame] @ self->curFrame = newFp
+ str r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+ mov r9, r3 @ r9<- glue->self (preserve)
+
+ mov r2, r0 @ r2<- methodToCall
+ mov r0, r1 @ r0<- newFp (points to args)
+ add r1, rGLUE, #offGlue_retval @ r1<- &retval
+
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ b .Lskip
+ .type dalvik_mterp, %function
+dalvik_mterp:
+ .fnstart
+ MTERP_ENTRY1
+ MTERP_ENTRY2
+.Lskip:
+#endif
+
+ @mov lr, pc @ set return addr
+ @ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ LDR_PC_LR "[r2, #offMethod_nativeFunc]"
+
+ @ native return; r9=self, r10=newSaveArea
+ @ equivalent to dvmPopJniLocals
+ ldr r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+ ldr r1, [r9, #offThread_exception] @ check for exception
+ str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
+ cmp r1, #0 @ null?
+ str r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+ bne common_exceptionThrown @ no, handle exception
+
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+.LstackOverflow:
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- self
+ bl dvmHandleStackOverflow
+ b common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+ .fnend
+#endif
+
+
+ /*
+ * Common code for method invocation, calling through "glue code".
+ *
+ * TODO: now that we have range and non-range invoke handlers, this
+ * needs to be split into two. Maybe just create entry points
+ * that set r9 and jump here?
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ * r9 is "bool methodCallRange", indicating if this is a /range variant
+ */
+ .if 0
+.LinvokeOld:
+ sub sp, sp, #8 @ space for args + pad
+ FETCH(ip, 2) @ ip<- FEDC or CCCC
+ mov r2, r0 @ A2<- methodToCall
+ mov r0, rGLUE @ A0<- glue
+ SAVE_PC_FP_TO_GLUE() @ export state to "glue"
+ mov r1, r9 @ A1<- methodCallRange
+ mov r3, rINST, lsr #8 @ A3<- AA
+ str ip, [sp, #0] @ A4<- ip
+ bl dvmMterp_invokeMethod @ call the C invokeMethod
+ add sp, sp, #8 @ remove arg area
+ b common_resumeAfterGlueCall @ continue to next instruction
+ .endif
+
+
+
+/*
+ * Common code for handling a return instruction.
+ *
+ * This does not return.
+ */
+common_returnFromMethod:
+.LreturnNew:
+ mov r0, #kInterpEntryReturn
+ mov r9, #0
+ bl common_periodicChecks
+
+ SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
+ ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+ ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+ ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ @ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ cmp r2, #0 @ is this a break frame?
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+ mov r1, #0 @ "want switch" = false
+ beq common_gotoBail @ break frame, bail out completely
+
+ PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+ str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
+#if defined(WITH_JIT)
+ ldr r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr
+ GET_JIT_PROF_TABLE(r0)
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r3, #0 @ caller is compiled code
+ blxne r3
+ 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
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+ /*
+ * Return handling, calls through "glue code".
+ */
+ .if 0
+.LreturnOld:
+ SAVE_PC_FP_TO_GLUE() @ export state
+ mov r0, rGLUE @ arg to function
+ bl dvmMterp_returnFromMethod
+ b common_resumeAfterGlueCall
+ .endif
+
+
+/*
+ * Somebody has thrown an exception. Handle it.
+ *
+ * If the exception processing code returns to us (instead of falling
+ * out of the interpreter), continue with whatever the next instruction
+ * now happens to be.
+ *
+ * This does not return.
+ */
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
+common_exceptionThrown:
+.LexceptionNew:
+ mov r0, #kInterpEntryThrow
+ mov r9, #0
+ bl common_periodicChecks
+
+#if defined(WITH_JIT)
+ mov r2,#kJitTSelectAbort @ abandon trace selection in progress
+ str r2,[rGLUE,#offGlue_jitState]
+#endif
+
+ ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self
+ ldr r9, [r10, #offThread_exception] @ r9<- self->exception
+ mov r1, r10 @ r1<- self
+ mov r0, r9 @ r0<- exception
+ bl dvmAddTrackedAlloc @ don't let the exception be GCed
+ mov r3, #0 @ r3<- NULL
+ str r3, [r10, #offThread_exception] @ self->exception = NULL
+
+ /* set up args and a local for "&fp" */
+ /* (str sp, [sp, #-4]! would be perfect here, but is discouraged) */
+ str rFP, [sp, #-4]! @ *--sp = fp
+ mov ip, sp @ ip<- &fp
+ mov r3, #0 @ r3<- false
+ str ip, [sp, #-4]! @ *--sp = &fp
+ ldr r1, [rGLUE, #offGlue_method] @ r1<- glue->method
+ mov r0, r10 @ r0<- self
+ ldr r1, [r1, #offMethod_insns] @ r1<- method->insns
+ mov r2, r9 @ r2<- exception
+ sub r1, rPC, r1 @ r1<- pc - method->insns
+ mov r1, r1, asr #1 @ r1<- offset in code units
+
+ /* call, r0 gets catchRelPc (a code-unit offset) */
+ bl dvmFindCatchBlock @ call(self, relPc, exc, scan?, &fp)
+
+ /* fix earlier stack overflow if necessary; may trash rFP */
+ ldrb r1, [r10, #offThread_stackOverflowed]
+ cmp r1, #0 @ did we overflow earlier?
+ beq 1f @ no, skip ahead
+ mov rFP, r0 @ save relPc result in rFP
+ mov r0, r10 @ r0<- self
+ bl dvmCleanupStackOverflow @ call(self)
+ mov r0, rFP @ restore result
+1:
+
+ /* update frame pointer and check result from dvmFindCatchBlock */
+ ldr rFP, [sp, #4] @ retrieve the updated rFP
+ cmp r0, #0 @ is catchRelPc < 0?
+ add sp, sp, #8 @ restore stack
+ bmi .LnotCaughtLocally
+
+ /* adjust locals to match self->curFrame and updated PC */
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- new save area
+ ldr r1, [r1, #offStackSaveArea_method] @ r1<- new method
+ str r1, [rGLUE, #offGlue_method] @ glue->method = new method
+ ldr r2, [r1, #offMethod_clazz] @ r2<- method->clazz
+ ldr r3, [r1, #offMethod_insns] @ r3<- method->insns
+ ldr r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
+ add rPC, r3, r0, asl #1 @ rPC<- method->insns + catchRelPc
+ str r2, [rGLUE, #offGlue_methodClassDex] @ glue->pDvmDex = meth...
+
+ /* release the tracked alloc on the exception */
+ mov r0, r9 @ r0<- exception
+ mov r1, r10 @ r1<- self
+ bl dvmReleaseTrackedAlloc @ release the exception
+
+ /* restore the exception if the handler wants it */
+ FETCH_INST() @ load rINST from rPC
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ cmp ip, #OP_MOVE_EXCEPTION @ is it "move-exception"?
+ streq r9, [r10, #offThread_exception] @ yes, restore the exception
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+.LnotCaughtLocally: @ r9=exception, r10=self
+ /* fix stack overflow if necessary */
+ ldrb r1, [r10, #offThread_stackOverflowed]
+ cmp r1, #0 @ did we overflow earlier?
+ movne r0, r10 @ if yes: r0<- self
+ blne dvmCleanupStackOverflow @ if yes: call(self)
+
+ @ may want to show "not caught locally" debug messages here
+#if DVM_SHOW_EXCEPTION >= 2
+ /* call __android_log_print(prio, tag, format, ...) */
+ /* "Exception %s from %s:%d not caught locally" */
+ @ dvmLineNumFromPC(method, pc - method->insns)
+ ldr r0, [rGLUE, #offGlue_method]
+ ldr r1, [r0, #offMethod_insns]
+ sub r1, rPC, r1
+ asr r1, r1, #1
+ bl dvmLineNumFromPC
+ str r0, [sp, #-4]!
+ @ dvmGetMethodSourceFile(method)
+ ldr r0, [rGLUE, #offGlue_method]
+ bl dvmGetMethodSourceFile
+ str r0, [sp, #-4]!
+ @ exception->clazz->descriptor
+ ldr r3, [r9, #offObject_clazz]
+ ldr r3, [r3, #offClassObject_descriptor]
+ @
+ ldr r2, strExceptionNotCaughtLocally
+ ldr r1, strLogTag
+ mov r0, #3 @ LOG_DEBUG
+ bl __android_log_print
+#endif
+ str r9, [r10, #offThread_exception] @ restore exception
+ mov r0, r9 @ r0<- exception
+ mov r1, r10 @ r1<- self
+ bl dvmReleaseTrackedAlloc @ release the exception
+ mov r1, #0 @ "want switch" = false
+ b common_gotoBail @ bail out
+
+
+ /*
+ * Exception handling, calls through "glue code".
+ */
+ .if 0
+.LexceptionOld:
+ SAVE_PC_FP_TO_GLUE() @ export state
+ mov r0, rGLUE @ arg to function
+ bl dvmMterp_exceptionThrown
+ b common_resumeAfterGlueCall
+ .endif
+
+
+/*
+ * After returning from a "glued" function, pull out the updated
+ * values and start executing at the next instruction.
+ */
+common_resumeAfterGlueCall:
+ LOAD_PC_FP_FROM_GLUE() @ pull rPC and rFP out of glue
+ FETCH_INST() @ load rINST from rPC
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Invalid array index.
+ */
+common_errArrayIndex:
+ EXPORT_PC()
+ ldr r0, strArrayIndexException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Invalid array value.
+ */
+common_errArrayStore:
+ EXPORT_PC()
+ ldr r0, strArrayStoreException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+ EXPORT_PC()
+ ldr r0, strArithmeticException
+ ldr r1, strDivideByZero
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ */
+common_errNegativeArraySize:
+ EXPORT_PC()
+ ldr r0, strNegativeArraySizeException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ */
+common_errNoSuchMethod:
+ EXPORT_PC()
+ ldr r0, strNoSuchMethodError
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * We encountered a null object when we weren't expecting one. We
+ * export the PC, throw a NullPointerException, and goto the exception
+ * processing code.
+ */
+common_errNullObject:
+ EXPORT_PC()
+ ldr r0, strNullPointerException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * For debugging, cause an immediate fault. The source address will
+ * be in lr (use a bl instruction to jump here).
+ */
+common_abort:
+ ldr pc, .LdeadFood
+.LdeadFood:
+ .word 0xdeadf00d
+
+/*
+ * Spit out a "we were here", preserving all registers. (The attempt
+ * to save ip won't work, but we need to save an even number of
+ * registers for EABI 64-bit stack alignment.)
+ */
+ .macro SQUEAK num
+common_squeak\num:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ ldr r0, strSqueak
+ mov r1, #\num
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+ .endm
+
+ SQUEAK 0
+ SQUEAK 1
+ SQUEAK 2
+ SQUEAK 3
+ SQUEAK 4
+ SQUEAK 5
+
+/*
+ * Spit out the number in r0, preserving registers.
+ */
+common_printNum:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ mov r1, r0
+ ldr r0, strSqueak
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Print a newline, preserving registers.
+ */
+common_printNewline:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ ldr r0, strNewline
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+ /*
+ * Print the 32-bit quantity in r0 as a hex value, preserving registers.
+ */
+common_printHex:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ mov r1, r0
+ ldr r0, strPrintHex
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Print the 64-bit quantity in r0-r1, preserving registers.
+ */
+common_printLong:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ mov r3, r1
+ mov r2, r0
+ ldr r0, strPrintLong
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Print full method info. Pass the Method* in r0. Preserves regs.
+ */
+common_printMethod:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bl dvmMterpPrintMethod
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Call a C helper function that dumps regs and possibly some
+ * additional info. Requires the C function to be compiled in.
+ */
+ .if 0
+common_dumpRegs:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bl dvmMterpDumpArmRegs
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+ .endif
+
+#if 0
+/*
+ * Experiment on VFP mode.
+ *
+ * uint32_t setFPSCR(uint32_t val, uint32_t mask)
+ *
+ * Updates the bits specified by "mask", setting them to the values in "val".
+ */
+setFPSCR:
+ and r0, r0, r1 @ make sure no stray bits are set
+ fmrx r2, fpscr @ get VFP reg
+ mvn r1, r1 @ bit-invert mask
+ and r2, r2, r1 @ clear masked bits
+ orr r2, r2, r0 @ set specified bits
+ fmxr fpscr, r2 @ set VFP reg
+ mov r0, r2 @ return new value
+ bx lr
+
+ .align 2
+ .global dvmConfigureFP
+ .type dvmConfigureFP, %function
+dvmConfigureFP:
+ stmfd sp!, {ip, lr}
+ /* 0x03000000 sets DN/FZ */
+ /* 0x00009f00 clears the six exception enable flags */
+ bl common_squeak0
+ mov r0, #0x03000000 @ r0<- 0x03000000
+ add r1, r0, #0x9f00 @ r1<- 0x03009f00
+ bl setFPSCR
+ ldmfd sp!, {ip, pc}
+#endif
+
+
+/*
+ * String references, must be close to the code that uses them.
+ */
+ .align 2
+strArithmeticException:
+ .word .LstrArithmeticException
+strArrayIndexException:
+ .word .LstrArrayIndexException
+strArrayStoreException:
+ .word .LstrArrayStoreException
+strDivideByZero:
+ .word .LstrDivideByZero
+strNegativeArraySizeException:
+ .word .LstrNegativeArraySizeException
+strNoSuchMethodError:
+ .word .LstrNoSuchMethodError
+strNullPointerException:
+ .word .LstrNullPointerException
+
+strLogTag:
+ .word .LstrLogTag
+strExceptionNotCaughtLocally:
+ .word .LstrExceptionNotCaughtLocally
+
+strNewline:
+ .word .LstrNewline
+strSqueak:
+ .word .LstrSqueak
+strPrintHex:
+ .word .LstrPrintHex
+strPrintLong:
+ .word .LstrPrintLong
+
+/*
+ * Zero-terminated ASCII string data.
+ *
+ * On ARM we have two choices: do like gcc does, and LDR from a .word
+ * with the address, or use an ADR pseudo-op to get the address
+ * directly. ADR saves 4 bytes and an indirection, but it's using a
+ * PC-relative addressing mode and hence has a limited range, which
+ * makes it not work well with mergeable string sections.
+ */
+ .section .rodata.str1.4,"aMS",%progbits,1
+
+.LstrBadEntryPoint:
+ .asciz "Bad entry point %d\n"
+.LstrArithmeticException:
+ .asciz "Ljava/lang/ArithmeticException;"
+.LstrArrayIndexException:
+ .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
+.LstrArrayStoreException:
+ .asciz "Ljava/lang/ArrayStoreException;"
+.LstrClassCastException:
+ .asciz "Ljava/lang/ClassCastException;"
+.LstrDivideByZero:
+ .asciz "divide by zero"
+.LstrFilledNewArrayNotImpl:
+ .asciz "filled-new-array only implemented for objects and 'int'"
+.LstrInternalError:
+ .asciz "Ljava/lang/InternalError;"
+.LstrInstantiationError:
+ .asciz "Ljava/lang/InstantiationError;"
+.LstrNegativeArraySizeException:
+ .asciz "Ljava/lang/NegativeArraySizeException;"
+.LstrNoSuchMethodError:
+ .asciz "Ljava/lang/NoSuchMethodError;"
+.LstrNullPointerException:
+ .asciz "Ljava/lang/NullPointerException;"
+
+.LstrLogTag:
+ .asciz "mterp"
+.LstrExceptionNotCaughtLocally:
+ .asciz "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+ .asciz "\n"
+.LstrSqueak:
+ .asciz "<%d>"
+.LstrPrintHex:
+ .asciz "<0x%x>"
+.LstrPrintLong:
+ .asciz "<%lld>"
+
+
diff --git a/vm/mterp/out/InterpAsm-armv5te.S b/vm/mterp/out/InterpAsm-armv5te.S
index 9987ff5..3f2069c 100644
--- a/vm/mterp/out/InterpAsm-armv5te.S
+++ b/vm/mterp/out/InterpAsm-armv5te.S
@@ -40,7 +40,9 @@
r0 holds returns of <= 4 bytes
r0-r1 hold returns of 8 bytes, low word in r0
-Callee must save/restore r4+ (except r12) if it modifies them.
+Callee must save/restore r4+ (except r12) if it modifies them. If VFP
+is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
+s0-s15 (d0-d7, q0-a3) do not need to be.
Stack is "full descending". Only the arguments that don't fit in the first 4
registers are placed on the stack. "sp" points at the first stacked argument
@@ -61,8 +63,8 @@
r4 rPC interpreted program counter, used for fetching instructions
r5 rFP interpreted frame pointer, used for accessing locals and args
r6 rGLUE MterpGlue pointer
- r7 rIBASE interpreted instruction base pointer, used for computed goto
- r8 rINST first 16-bit code unit of current instruction
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
Macros are provided for common operations. Each macro MUST emit only
one instruction to make instruction-counting easier. They MUST NOT alter
@@ -73,8 +75,8 @@
#define rPC r4
#define rFP r5
#define rGLUE r6
-#define rIBASE r7
-#define rINST r8
+#define rINST r7
+#define rIBASE r8
/* save/restore the PC and/or FP from the glue struct */
#define LOAD_PC_FROM_GLUE() ldr rPC, [rGLUE, #offGlue_pc]
@@ -124,6 +126,13 @@
#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!
/*
+ * The operation performed here is similar to FETCH_ADVANCE_INST, except the
+ * src and dest registers are parameterized (not hard-wired to rPC and rINST).
+ */
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ ldrh _dreg, [_sreg, #(_count*2)]!
+
+/*
* Fetch the next instruction from an offset specified by _reg. Updates
* rPC to point to the next instruction. "_reg" must specify the distance
* in bytes, *not* 16-bit code units, and may be a signed value.
@@ -157,10 +166,17 @@
#define GET_INST_OPCODE(_reg) and _reg, rINST, #255
/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+#define GET_PREFETCHED_OPCODE(_oreg, _ireg) and _oreg, _ireg, #255
+
+/*
* Begin executing the opcode in _reg. Because this only jumps within the
* interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
*/
#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFEQ(_reg) addeq pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFNE(_reg) addne pc, rIBASE, _reg, lsl #6
/*
* Get/set the 32-bit value from a Dalvik register.
@@ -168,6 +184,17 @@
#define GET_VREG(_reg, _vreg) ldr _reg, [rFP, _vreg, lsl #2]
#define SET_VREG(_reg, _vreg) str _reg, [rFP, _vreg, lsl #2]
+#if defined(WITH_JIT)
+#define GET_JIT_ENABLED(_reg) ldr _reg,[rGLUE,#offGlue_jitEnabled]
+#define GET_JIT_PROF_TABLE(_reg) ldr _reg,[rGLUE,#offGlue_pJitProfTable]
+#endif
+
+/*
+ * Convert a virtual register index into an address.
+ */
+#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
+ add _reg, rFP, _vreg, lsl #2
+
/*
* This is a #include, not a %include, because we want the C pre-processor
* to expand the macros into assembler assignment statements.
@@ -282,10 +309,21 @@
cmp r1, #kInterpEntryInstr @ usual case?
bne .Lnot_instr @ no, handle it
+#if defined(WITH_JIT)
+.Lno_singleStep:
+ /* Entry is always a possible trace start */
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
/* start executing the instruction at rPC */
FETCH_INST() @ load rINST from rPC
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
.Lnot_instr:
cmp r1, #kInterpEntryReturn @ were we returning from a method?
@@ -295,6 +333,22 @@
cmp r1, #kInterpEntryThrow @ were we throwing an exception?
beq common_exceptionThrown
+#if defined(WITH_JIT)
+.Lnot_throw:
+ ldr r0,[rGLUE, #offGlue_jitResume]
+ ldr r2,[rGLUE, #offGlue_jitResumePC]
+ cmp r1, #kInterpEntryResume @ resuming after Jit single-step?
+ bne .Lbad_arg
+ cmp rPC,r2
+ bne .Lno_singleStep @ must have branched, don't resume
+ mov r1, #kInterpEntryInstr
+ strb r1, [rGLUE, #offGlue_entryPoint]
+ ldr rINST, .LdvmCompilerTemplate
+ bx r0 @ re-enter the translation
+.LdvmCompilerTemplate:
+ .word dvmCompilerTemplateStart
+#endif
+
.Lbad_arg:
ldr r0, strBadEntryPoint
@ r1 holds value of entryPoint
@@ -450,7 +504,7 @@
add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
add r2, rFP, r2, lsl #2 @ r2<- &fp[AAAA]
ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
- FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
GOTO_OPCODE(ip) @ jump to next instruction
@@ -818,9 +872,7 @@
GET_VREG(r1, r2) @ r1<- vAA (object)
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
cmp r1, #0 @ null object?
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC() @ export PC so we can grab stack trace
-#endif
+ EXPORT_PC() @ need for precise GC, MONITOR_TRACKING
beq common_errNullObject @ null object, throw an exception
FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
bl dvmLockObject @ call(self, obj)
@@ -956,11 +1008,9 @@
cmp r1, #CLASS_INITIALIZED @ has class been initialized?
bne .LOP_NEW_INSTANCE_needinit @ no, init class now
.LOP_NEW_INSTANCE_initialized: @ r0=class
- ldr r3, [r0, #offClassObject_accessFlags] @ r3<- clazz->accessFlags
- tst r3, #(ACC_INTERFACE|ACC_ABSTRACT) @ abstract or interface?
mov r1, #ALLOC_DONT_TRACK @ flags for alloc call
- beq .LOP_NEW_INSTANCE_finish @ concrete class, continue
- b .LOP_NEW_INSTANCE_abstract @ fail
+ bl dvmAllocObject @ r0<- new object
+ b .LOP_NEW_INSTANCE_finish @ continue
/* ------------------------------ */
.balign 64
@@ -1095,10 +1145,18 @@
movs r9, r0, asr #24 @ r9<- ssssssAA (sign-extended)
mov r9, r9, lsl #1 @ r9<- byte offset
bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
+#endif
/* ------------------------------ */
.balign 64
@@ -1114,9 +1172,18 @@
FETCH_S(r0, 1) @ r0<- ssssAAAA (sign-extended)
movs r9, r0, asl #1 @ r9<- byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/* ------------------------------ */
@@ -1141,10 +1208,18 @@
orrs r0, r0, r1, lsl #16 @ r0<- AAAAaaaa, check sign
mov r9, r0, asl #1 @ r9<- byte offset
ble common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
-
+#endif
/* ------------------------------ */
.balign 64
@@ -1170,9 +1245,18 @@
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/* ------------------------------ */
@@ -1200,9 +1284,18 @@
movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1449,9 +1542,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1479,9 +1579,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1509,9 +1616,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1539,9 +1653,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1569,9 +1690,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1599,9 +1727,16 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ yes, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1626,9 +1761,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1653,9 +1798,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1680,9 +1835,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1707,9 +1872,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1734,9 +1909,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -1761,9 +1946,19 @@
FETCH_S(r9, 1) @ r9<- branch offset, in code units
movs r9, r9, asl #1 @ convert to bytes, check sign
bmi common_backwardBranch @ backward branch, do periodic checks
-1: FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
@@ -3826,20 +4021,23 @@
*/
d2i_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
- ldr r2, .LOP_DOUBLE_TO_INT_maxlo @ (double)maxint, lo
- ldr r3, .LOP_DOUBLE_TO_INT_maxhi @ (double)maxint, hi
+ mov r2, #0x80000000 @ maxint, as a double (low word)
+ mov r2, r2, asr #9 @ 0xffc00000
sub sp, sp, #4 @ align for EABI
- mov r4, r0 @ save r0
+ mvn r3, #0xbe000000 @ maxint, as a double (high word)
+ sub r3, r3, #0x00200000 @ 0x41dfffff
+ mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxint?
cmp r0, #0 @ nonzero == yes
- mvnne r0, #0x80000000 @ return maxint (7fffffff)
+ mvnne r0, #0x80000000 @ return maxint (0x7fffffff)
bne 1f
mov r0, r4 @ recover arg
mov r1, r5
- ldr r3, .LOP_DOUBLE_TO_INT_min @ (double)minint, hi
- mov r2, #0 @ (double)minint, lo
+ mov r3, #0xc1000000 @ minint, as a double (high word)
+ add r3, r3, #0x00e00000 @ 0xc1e00000
+ mov r2, #0 @ minint, as a double (low word)
bl __aeabi_dcmple @ is arg <= minint?
cmp r0, #0 @ nonzero == yes
movne r0, #0x80000000 @ return minint (80000000)
@@ -3860,13 +4058,6 @@
1:
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-
-.LOP_DOUBLE_TO_INT_maxlo:
- .word 0xffc00000 @ maxint, as a double (low word)
-.LOP_DOUBLE_TO_INT_maxhi:
- .word 0x41dfffff @ maxint, as a double (high word)
-.LOP_DOUBLE_TO_INT_min:
- .word 0xc1e00000 @ minint, as a double (high word)
#endif
@@ -5378,8 +5569,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5418,8 +5609,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5459,8 +5650,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5499,8 +5690,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5540,8 +5731,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 1
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5580,8 +5771,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5620,8 +5811,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5660,8 +5851,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5700,8 +5891,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5740,8 +5931,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -5780,8 +5971,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6224,8 +6415,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6264,8 +6455,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6304,8 +6495,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6344,8 +6535,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -6385,8 +6576,8 @@
mov r9, rINST, lsr #8 @ r9<- A+
mov r3, rINST, lsr #12 @ r3<- B
and r9, r9, #15
- GET_VREG(r0, r9) @ r0<- vA
GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
.if 0
cmp r1, #0 @ is second operand zero?
beq common_errDivideByZero
@@ -7435,11 +7626,20 @@
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_ED: /* 0xed */
-/* File: armv5te/OP_UNUSED_ED.S */
-/* File: armv5te/unused.S */
- bl common_abort
-
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR.S */
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ FETCH(r2, 1) @ r2<- BBBB
+ EXPORT_PC() @ export the PC
+ mov r1, rINST, lsr #8 @ r1<- AA
+ bl dvmThrowVerificationError @ always throws
+ b common_exceptionThrown @ handle exception
/* ------------------------------ */
@@ -7951,8 +8151,7 @@
/* continuation for OP_NEW_INSTANCE */
.balign 32 @ minimize cache lines
-.LOP_NEW_INSTANCE_finish: @ r0=class
- bl dvmAllocObject @ r0<- new object
+.LOP_NEW_INSTANCE_finish: @ r0=new object
mov r3, rINST, lsr #8 @ r3<- AA
cmp r0, #0 @ failed?
beq common_exceptionThrown @ yes, handle the exception
@@ -7988,18 +8187,6 @@
bne .LOP_NEW_INSTANCE_resolved @ no, continue
b common_exceptionThrown @ yes, handle exception
- /*
- * We can't instantiate an abstract class or interface, so throw an
- * InstantiationError with the class descriptor as the message.
- *
- * r0 holds class object
- */
-.LOP_NEW_INSTANCE_abstract:
- ldr r1, [r0, #offClassObject_descriptor]
- ldr r0, .LstrInstantiationErrorPtr
- bl dvmThrowExceptionWithClassMessage
- b common_exceptionThrown
-
.LstrInstantiationErrorPtr:
.word .LstrInstantiationError
@@ -9136,10 +9323,11 @@
*/
d2l_doconv:
stmfd sp!, {r4, r5, lr} @ save regs
- ldr r3, .LOP_DOUBLE_TO_LONG_max @ (double)maxlong, hi
+ mov r3, #0x43000000 @ maxlong, as a double (high word)
+ add r3, #0x00e00000 @ 0x43e00000
+ mov r2, #0 @ maxlong, as a double (low word)
sub sp, sp, #4 @ align for EABI
- mov r2, #0 @ (double)maxlong, lo
- mov r4, r0 @ save r0
+ mov r4, r0 @ save a copy of r0
mov r5, r1 @ and r1
bl __aeabi_dcmpge @ is arg >= maxlong?
cmp r0, #0 @ nonzero == yes
@@ -9149,8 +9337,9 @@
mov r0, r4 @ recover arg
mov r1, r5
- ldr r3, .LOP_DOUBLE_TO_LONG_min @ (double)minlong, hi
- mov r2, #0 @ (double)minlong, lo
+ mov r3, #0xc3000000 @ minlong, as a double (high word)
+ add r3, #0x00e00000 @ 0xc3e00000
+ mov r2, #0 @ minlong, as a double (low word)
bl __aeabi_dcmple @ is arg <= minlong?
cmp r0, #0 @ nonzero == yes
movne r0, #0 @ return minlong (8000000000000000)
@@ -9174,11 +9363,6 @@
add sp, sp, #4
ldmfd sp!, {r4, r5, pc}
-.LOP_DOUBLE_TO_LONG_max:
- .word 0x43e00000 @ maxlong, as a double (high word)
-.LOP_DOUBLE_TO_LONG_min:
- .word 0xc3e00000 @ minlong, as a double (high word)
-
/* continuation for OP_MUL_LONG */
@@ -9280,15 +9464,191 @@
dvmAsmSisterEnd:
/* File: armv5te/footer.S */
+
/*
* ===========================================================================
* Common subroutines and data
* ===========================================================================
*/
+
+
.text
.align 2
+#if defined(WITH_JIT)
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ mov rPC, r0
+#ifdef EXIT_STATS
+ mov r0,lr
+ bl dvmBumpPunt;
+#endif
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * r0 <= PC
+ * r1 <= PC of resume instruction
+ * lr <= resume point in translation
+ */
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ str lr,[rGLUE,#offGlue_jitResume]
+ str r1,[rGLUE,#offGlue_jitResumePC]
+ mov r1,#kInterpEntryInstr
+ @ enum is 4 byte in aapcs-EABI
+ str r1, [rGLUE, #offGlue_entryPoint]
+ mov rPC,r0
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ mov r2,#kJitSingleStep @ Ask for single step and then revert
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp to bail to debug interp
+ b common_gotoBail
+
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToTraceSelect
+dvmJitToTraceSelect:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq 2f
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/* No translation, so request one if profiling isn't disabled*/
+2:
+ adrl rIBASE, dvmAsmInstructionStart
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0, #0
+ bne common_selectTrace
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+#ifdef EXIT_STATS
+ bl dvmBumpNormal
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq toInterpreter @ go if not, otherwise do chain
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/*
+ * 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 EXIT_STATS
+ bl dvmBumpNoChain
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rGLUE & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+toInterpreter:
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ 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
+ * next instruction to execute, and rINST should be already loaded with
+ * the next opcode word, and r0 holds a pointer to the jit profile
+ * table (pJitProfTable).
+ */
+common_testUpdateProfile:
+ cmp r0,#0
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */
+
+common_updateProfile:
+ eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+ lsl r3,r3,#23 @ shift out excess 511
+ ldrb r1,[r0,r3,lsr #23] @ get counter
+ GET_INST_OPCODE(ip)
+ subs r1,r1,#1 @ decrement counter
+ strb r1,[r0,r3,lsr #23] @ and store it
+ GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
+
+/*
+ * Here, we switch to the debug interpreter to request
+ * trace selection. First, though, check to see if there
+ * is already a native translation in place (and, if so,
+ * jump to it now).
+ */
+ mov r1,#255
+ strb r1,[r0,r3,lsr #23] @ reset counter
+ EXPORT_PC()
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
+ cmp r0,#0
+ beq common_selectTrace
+ bxne r0 @ jump to the translation
+common_selectTrace:
+ mov r2,#kJitTSelectRequest @ ask for trace selection
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp
+ b common_gotoBail
+
+#endif
+
/*
* Common code when a backward branch is taken.
*
@@ -9298,9 +9658,18 @@
common_backwardBranch:
mov r0, #kInterpEntryInstr
bl common_periodicChecks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
GET_INST_OPCODE(ip) @ extract opcode from rINST
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/*
@@ -9336,7 +9705,7 @@
#endif
cmp r3, #0 @ suspend pending?
- bne 2f @ yes, check suspend
+ bne 2f @ yes, do full suspension check
#if defined(WITH_DEBUGGER) || defined(WITH_PROFILER)
# if defined(WITH_DEBUGGER) && defined(WITH_PROFILER)
@@ -9354,6 +9723,7 @@
2: @ check suspend
ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ need for precise GC
b dvmCheckSuspendPending @ suspend if necessary, then return
3: @ debugger/profiler enabled, bail out
@@ -9401,10 +9771,12 @@
@ (very few methods have > 10 args; could unroll for common cases)
add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC]
sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
1: ldr r1, [r3], #4 @ val = *fp++
subs r2, r2, #1 @ count--
str r1, [r10], #4 @ *outs++ = val
bne 1b @ ...while count != 0
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
b .LinvokeArgsDone
/*
@@ -9418,47 +9790,50 @@
@ prepare to copy args to "outs" area of current frame
movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero
SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
- beq .LinvokeArgsDone @ if no args, skip the rest
- FETCH(r1, 2) @ r1<- GFED
+ FETCH(r1, 2) @ r1<- GFED (load here to hide latency)
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ beq .LinvokeArgsDone
- @ r0=methodToCall, r1=GFED, r2=count, r10=outs
+ @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
.LinvokeNonRange:
rsb r2, r2, #5 @ r2<- 5-r2
add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each
bl common_abort @ (skipped due to ARM prefetch)
5: and ip, rINST, #0x0f00 @ isolate A
- ldr r3, [rFP, ip, lsr #6] @ r3<- vA (shift right 8, left 2)
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2)
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vA
+ str r2, [r10, #-4]! @ *--outs = vA
4: and ip, r1, #0xf000 @ isolate G
- ldr r3, [rFP, ip, lsr #10] @ r3<- vG (shift right 12, left 2)
+ ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2)
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vG
+ str r2, [r10, #-4]! @ *--outs = vG
3: and ip, r1, #0x0f00 @ isolate F
- ldr r3, [rFP, ip, lsr #6] @ r3<- vF
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vF
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vF
+ str r2, [r10, #-4]! @ *--outs = vF
2: and ip, r1, #0x00f0 @ isolate E
- ldr r3, [rFP, ip, lsr #2] @ r3<- vE
+ ldr r2, [rFP, ip, lsr #2] @ r2<- vE
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vE
+ str r2, [r10, #-4]! @ *--outs = vE
1: and ip, r1, #0x000f @ isolate D
- ldr r3, [rFP, ip, lsl #2] @ r3<- vD
+ ldr r2, [rFP, ip, lsl #2] @ r2<- vD
mov r0, r0 @ nop
- str r3, [r10, #-4]! @ *--outs = vD
+ str r2, [r10, #-4]! @ *--outs = vD
0: @ fall through to .LinvokeArgsDone
-.LinvokeArgsDone: @ r0=methodToCall
+.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
+ ldr r2, [r0, #offMethod_insns] @ r2<- method->insns
+ ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz
@ find space for the new stack frame, check for overflow
SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
- ldrh r2, [r0, #offMethod_registersSize] @ r2<- methodToCall->regsSize
- ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
- sub r1, r1, r2, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize)
SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea
@ bl common_dumpRegs
ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
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
@ set up newSaveArea
@@ -9468,9 +9843,11 @@
#endif
str rFP, [r10, #offStackSaveArea_prevFrame]
str rPC, [r10, #offStackSaveArea_savedPc]
+#if defined(WITH_JIT)
+ mov r9, #0
+ str r9, [r10, #offStackSaveArea_returnAddr]
+#endif
str r0, [r10, #offStackSaveArea_method]
-
- ldr r3, [r0, #offMethod_accessFlags] @ r3<- methodToCall->accessFlags
tst r3, #ACC_NATIVE
bne .LinvokeNative
@@ -9489,19 +9866,31 @@
ldmfd sp!, {r0-r3}
*/
- @ Update "glue" values for the new method
- @ r0=methodToCall, r1=newFp
- ldr r3, [r0, #offMethod_clazz] @ r3<- method->clazz
- str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
- ldr r3, [r3, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
- ldr rPC, [r0, #offMethod_insns] @ rPC<- method->insns
- str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+ ldrh r9, [r2] @ r9 <- load INST from new PC
+ ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ mov rPC, r2 @ publish new rPC
ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
- FETCH_INST() @ load rINST from rPC
+
+ @ Update "glue" values for the new method
+ @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
mov rFP, r1 @ fp = newFp
- GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ cmp r0,#0
+ bne common_updateProfile
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
.LinvokeNative:
@ Prep for the native call
@@ -9594,22 +9983,36 @@
SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+ ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
@ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
cmp r2, #0 @ is this a break frame?
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
mov r1, #0 @ "want switch" = false
beq common_gotoBail @ break frame, bail out completely
- ldr rPC, [r0, #offStackSaveArea_savedPc] @ pc = saveArea->savedPc
- ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
- str r2, [rGLUE, #offGlue_method] @ glue->method = newSave->method
+ PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
- ldr r1, [r2, #offMethod_clazz] @ r1<- method->clazz
- FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
- ldr r1, [r1, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+#if defined(WITH_JIT)
+ ldr r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr
+ GET_JIT_PROF_TABLE(r0)
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r3, #0 @ caller is compiled code
+ blxne r3
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
+ mov rPC, r9 @ publish new rPC
str r1, [rGLUE, #offGlue_methodClassDex]
GOTO_OPCODE(ip) @ jump to next instruction
+#endif
/*
* Return handling, calls through "glue code".
@@ -9632,12 +10035,19 @@
*
* This does not return.
*/
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
common_exceptionThrown:
.LexceptionNew:
mov r0, #kInterpEntryThrow
mov r9, #0
bl common_periodicChecks
+#if defined(WITH_JIT)
+ mov r2,#kJitTSelectAbort @ abandon trace selection in progress
+ str r2,[rGLUE,#offGlue_jitState]
+#endif
+
ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self
ldr r9, [r10, #offThread_exception] @ r9<- self->exception
mov r1, r10 @ r1<- self
@@ -9919,6 +10329,38 @@
bx lr
.endif
+#if 0
+/*
+ * Experiment on VFP mode.
+ *
+ * uint32_t setFPSCR(uint32_t val, uint32_t mask)
+ *
+ * Updates the bits specified by "mask", setting them to the values in "val".
+ */
+setFPSCR:
+ and r0, r0, r1 @ make sure no stray bits are set
+ fmrx r2, fpscr @ get VFP reg
+ mvn r1, r1 @ bit-invert mask
+ and r2, r2, r1 @ clear masked bits
+ orr r2, r2, r0 @ set specified bits
+ fmxr fpscr, r2 @ set VFP reg
+ mov r0, r2 @ return new value
+ bx lr
+
+ .align 2
+ .global dvmConfigureFP
+ .type dvmConfigureFP, %function
+dvmConfigureFP:
+ stmfd sp!, {ip, lr}
+ /* 0x03000000 sets DN/FZ */
+ /* 0x00009f00 clears the six exception enable flags */
+ bl common_squeak0
+ mov r0, #0x03000000 @ r0<- 0x03000000
+ add r1, r0, #0x9f00 @ r1<- 0x03009f00
+ bl setFPSCR
+ ldmfd sp!, {ip, pc}
+#endif
+
/*
* String references, must be close to the code that uses them.
diff --git a/vm/mterp/out/InterpAsm-armv7-a.S b/vm/mterp/out/InterpAsm-armv7-a.S
new file mode 100644
index 0000000..923084f
--- /dev/null
+++ b/vm/mterp/out/InterpAsm-armv7-a.S
@@ -0,0 +1,9908 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv7-a'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: armv5te/header.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.
+ */
+/*
+ * ARMv5 definitions and declarations.
+ */
+
+/*
+ARM EABI general notes:
+
+r0-r3 hold first 4 args to a method; they are not preserved across method calls
+r4-r8 are available for general use
+r9 is given special treatment in some situations, but not for us
+r10 (sl) seems to be generally available
+r11 (fp) is used by gcc (unless -fomit-frame-pointer is set)
+r12 (ip) is scratch -- not preserved across method calls
+r13 (sp) should be managed carefully in case a signal arrives
+r14 (lr) must be preserved
+r15 (pc) can be tinkered with directly
+
+r0 holds returns of <= 4 bytes
+r0-r1 hold returns of 8 bytes, low word in r0
+
+Callee must save/restore r4+ (except r12) if it modifies them. If VFP
+is present, registers s16-s31 (a/k/a d8-d15, a/k/a q4-q7) must be preserved,
+s0-s15 (d0-d7, q0-a3) do not need to be.
+
+Stack is "full descending". Only the arguments that don't fit in the first 4
+registers are placed on the stack. "sp" points at the first stacked argument
+(i.e. the 5th arg).
+
+VFP: single-precision results in s0, double-precision results in d0.
+
+In the EABI, "sp" must be 64-bit aligned on entry to a function, and any
+64-bit quantities (long long, double) must be 64-bit aligned.
+*/
+
+/*
+Mterp and ARM notes:
+
+The following registers have fixed assignments:
+
+ reg nick purpose
+ r4 rPC interpreted program counter, used for fetching instructions
+ r5 rFP interpreted frame pointer, used for accessing locals and args
+ r6 rGLUE MterpGlue pointer
+ r7 rINST first 16-bit code unit of current instruction
+ r8 rIBASE interpreted instruction base pointer, used for computed goto
+
+Macros are provided for common operations. Each macro MUST emit only
+one instruction to make instruction-counting easier. They MUST NOT alter
+unspecified registers or condition codes.
+*/
+
+/* single-purpose registers, given names for clarity */
+#define rPC r4
+#define rFP r5
+#define rGLUE r6
+#define rINST r7
+#define rIBASE r8
+
+/* save/restore the PC and/or FP from the glue struct */
+#define LOAD_PC_FROM_GLUE() ldr rPC, [rGLUE, #offGlue_pc]
+#define SAVE_PC_TO_GLUE() str rPC, [rGLUE, #offGlue_pc]
+#define LOAD_FP_FROM_GLUE() ldr rFP, [rGLUE, #offGlue_fp]
+#define SAVE_FP_TO_GLUE() str rFP, [rGLUE, #offGlue_fp]
+#define LOAD_PC_FP_FROM_GLUE() ldmia rGLUE, {rPC, rFP}
+#define SAVE_PC_FP_TO_GLUE() stmia rGLUE, {rPC, rFP}
+
+/*
+ * "export" the PC to the stack frame, f/b/o future exception objects. Must
+ * be done *before* something calls dvmThrowException.
+ *
+ * In C this is "SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc", i.e.
+ * fp - sizeof(StackSaveArea) + offsetof(SaveArea, xtra.currentPc)
+ *
+ * It's okay to do this more than once.
+ */
+#define EXPORT_PC() \
+ str rPC, [rFP, #(-sizeofStackSaveArea + offStackSaveArea_currentPc)]
+
+/*
+ * Given a frame pointer, find the stack save area.
+ *
+ * In C this is "((StackSaveArea*)(_fp) -1)".
+ */
+#define SAVEAREA_FROM_FP(_reg, _fpreg) \
+ sub _reg, _fpreg, #sizeofStackSaveArea
+
+/*
+ * Fetch the next instruction from rPC into rINST. Does not advance rPC.
+ */
+#define FETCH_INST() ldrh rINST, [rPC]
+
+/*
+ * Fetch the next instruction from the specified offset. Advances rPC
+ * to point to the next instruction. "_count" is in 16-bit code units.
+ *
+ * Because of the limited size of immediate constants on ARM, this is only
+ * suitable for small forward movements (i.e. don't try to implement "goto"
+ * with this).
+ *
+ * This must come AFTER anything that can throw an exception, or the
+ * exception catch may miss. (This also implies that it must come after
+ * EXPORT_PC().)
+ */
+#define FETCH_ADVANCE_INST(_count) ldrh rINST, [rPC, #(_count*2)]!
+
+/*
+ * The operation performed here is similar to FETCH_ADVANCE_INST, except the
+ * src and dest registers are parameterized (not hard-wired to rPC and rINST).
+ */
+#define PREFETCH_ADVANCE_INST(_dreg, _sreg, _count) \
+ ldrh _dreg, [_sreg, #(_count*2)]!
+
+/*
+ * Fetch the next instruction from an offset specified by _reg. Updates
+ * rPC to point to the next instruction. "_reg" must specify the distance
+ * in bytes, *not* 16-bit code units, and may be a signed value.
+ *
+ * We want to write "ldrh rINST, [rPC, _reg, lsl #2]!", but some of the
+ * bits that hold the shift distance are used for the half/byte/sign flags.
+ * In some cases we can pre-double _reg for free, so we require a byte offset
+ * here.
+ */
+#define FETCH_ADVANCE_INST_RB(_reg) ldrh rINST, [rPC, _reg]!
+
+/*
+ * Fetch a half-word code unit from an offset past the current PC. The
+ * "_count" value is in 16-bit code units. Does not advance rPC.
+ *
+ * The "_S" variant works the same but treats the value as signed.
+ */
+#define FETCH(_reg, _count) ldrh _reg, [rPC, #(_count*2)]
+#define FETCH_S(_reg, _count) ldrsh _reg, [rPC, #(_count*2)]
+
+/*
+ * Fetch one byte from an offset past the current PC. Pass in the same
+ * "_count" as you would for FETCH, and an additional 0/1 indicating which
+ * byte of the halfword you want (lo/hi).
+ */
+#define FETCH_B(_reg, _count, _byte) ldrb _reg, [rPC, #(_count*2+_byte)]
+
+/*
+ * Put the instruction's opcode field into the specified register.
+ */
+#define GET_INST_OPCODE(_reg) and _reg, rINST, #255
+
+/*
+ * Put the prefetched instruction's opcode field into the specified register.
+ */
+#define GET_PREFETCHED_OPCODE(_oreg, _ireg) and _oreg, _ireg, #255
+
+/*
+ * Begin executing the opcode in _reg. Because this only jumps within the
+ * interpreter, we don't have to worry about pre-ARMv5 THUMB interwork.
+ */
+#define GOTO_OPCODE(_reg) add pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFEQ(_reg) addeq pc, rIBASE, _reg, lsl #6
+#define GOTO_OPCODE_IFNE(_reg) addne pc, rIBASE, _reg, lsl #6
+
+/*
+ * Get/set the 32-bit value from a Dalvik register.
+ */
+#define GET_VREG(_reg, _vreg) ldr _reg, [rFP, _vreg, lsl #2]
+#define SET_VREG(_reg, _vreg) str _reg, [rFP, _vreg, lsl #2]
+
+#if defined(WITH_JIT)
+#define GET_JIT_ENABLED(_reg) ldr _reg,[rGLUE,#offGlue_jitEnabled]
+#define GET_JIT_PROF_TABLE(_reg) ldr _reg,[rGLUE,#offGlue_pJitProfTable]
+#endif
+
+/*
+ * Convert a virtual register index into an address.
+ */
+#define VREG_INDEX_TO_ADDR(_reg, _vreg) \
+ add _reg, rFP, _vreg, lsl #2
+
+/*
+ * This is a #include, not a %include, because we want the C pre-processor
+ * to expand the macros into assembler assignment statements.
+ */
+#include "../common/asm-constants.h"
+
+
+/* File: armv5te/platform.S */
+/*
+ * ===========================================================================
+ * 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
+
+
+/* File: armv5te/entry.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.
+ */
+/*
+ * Interpreter entry point.
+ */
+
+/*
+ * We don't have formal stack frames, so gdb scans upward in the code
+ * to find the start of the function (a label with the %function type),
+ * and then looks at the next few instructions to figure out what
+ * got pushed onto the stack. From this it figures out how to restore
+ * the registers, including PC, for the previous stack frame. If gdb
+ * sees a non-function label, it stops scanning, so either we need to
+ * have nothing but assembler-local labels between the entry point and
+ * the break, or we need to fake it out.
+ *
+ * When this is defined, we add some stuff to make gdb less confused.
+ */
+#define ASSIST_DEBUGGER 1
+
+ .text
+ .align 2
+ .global dvmMterpStdRun
+ .type dvmMterpStdRun, %function
+
+/*
+ * On entry:
+ * r0 MterpGlue* glue
+ *
+ * This function returns a boolean "changeInterp" value. The return comes
+ * via a call to dvmMterpStdBail().
+ */
+dvmMterpStdRun:
+#define MTERP_ENTRY1 \
+ .save {r4-r10,fp,lr}; \
+ stmfd sp!, {r4-r10,fp,lr} @ save 9 regs
+#define MTERP_ENTRY2 \
+ .pad #4; \
+ sub sp, sp, #4 @ align 64
+
+ .fnstart
+ MTERP_ENTRY1
+ MTERP_ENTRY2
+
+ /* save stack pointer, add magic word for debuggerd */
+ str sp, [r0, #offGlue_bailPtr] @ save SP for eventual return
+
+ /* set up "named" registers, figure out entry point */
+ mov rGLUE, r0 @ set rGLUE
+ ldrb r1, [r0, #offGlue_entryPoint] @ InterpEntry enum is char
+ LOAD_PC_FP_FROM_GLUE() @ load rPC and rFP from "glue"
+ adr rIBASE, dvmAsmInstructionStart @ set rIBASE
+ cmp r1, #kInterpEntryInstr @ usual case?
+ bne .Lnot_instr @ no, handle it
+
+#if defined(WITH_JIT)
+.Lno_singleStep:
+ /* Entry is always a possible trace start */
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
+ /* start executing the instruction at rPC */
+ FETCH_INST() @ load rINST from rPC
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+.Lnot_instr:
+ cmp r1, #kInterpEntryReturn @ were we returning from a method?
+ beq common_returnFromMethod
+
+.Lnot_return:
+ cmp r1, #kInterpEntryThrow @ were we throwing an exception?
+ beq common_exceptionThrown
+
+#if defined(WITH_JIT)
+.Lnot_throw:
+ ldr r0,[rGLUE, #offGlue_jitResume]
+ ldr r2,[rGLUE, #offGlue_jitResumePC]
+ cmp r1, #kInterpEntryResume @ resuming after Jit single-step?
+ bne .Lbad_arg
+ cmp rPC,r2
+ bne .Lno_singleStep @ must have branched, don't resume
+ mov r1, #kInterpEntryInstr
+ strb r1, [rGLUE, #offGlue_entryPoint]
+ ldr rINST, .LdvmCompilerTemplate
+ bx r0 @ re-enter the translation
+.LdvmCompilerTemplate:
+ .word dvmCompilerTemplateStart
+#endif
+
+.Lbad_arg:
+ ldr r0, strBadEntryPoint
+ @ r1 holds value of entryPoint
+ bl printf
+ bl dvmAbort
+ .fnend
+
+
+ .global dvmMterpStdBail
+ .type dvmMterpStdBail, %function
+
+/*
+ * Restore the stack pointer and PC from the save point established on entry.
+ * This is essentially the same as a longjmp, but should be cheaper. The
+ * last instruction causes us to return to whoever called dvmMterpStdRun.
+ *
+ * We pushed some registers on the stack in dvmMterpStdRun, then saved
+ * SP and LR. Here we restore SP, restore the registers, and then restore
+ * LR to PC.
+ *
+ * On entry:
+ * r0 MterpGlue* glue
+ * r1 bool changeInterp
+ */
+dvmMterpStdBail:
+ ldr sp, [r0, #offGlue_bailPtr] @ sp<- saved SP
+ mov r0, r1 @ return the changeInterp value
+ add sp, sp, #4 @ un-align 64
+ LDMFD_PC "r4-r10,fp" @ restore 9 regs and return
+
+
+/*
+ * String references.
+ */
+strBadEntryPoint:
+ .word .LstrBadEntryPoint
+
+
+
+ .global dvmAsmInstructionStart
+ .type dvmAsmInstructionStart, %function
+dvmAsmInstructionStart = .L_OP_NOP
+ .text
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NOP: /* 0x00 */
+/* File: armv5te/OP_NOP.S */
+ FETCH_ADVANCE_INST(1) @ advance to next instr, load rINST
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ .type dalvik_inst, %function
+dalvik_inst:
+ .fnstart
+ MTERP_ENTRY1
+ MTERP_ENTRY2
+ .fnend
+#endif
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE: /* 0x01 */
+/* File: armv6t2/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ ubfx r0, rINST, #8, #4 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r2, r0) @ fp[A]<- r2
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_FROM16: /* 0x02 */
+/* File: armv5te/OP_MOVE_FROM16.S */
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ mov r0, rINST, lsr #8 @ r0<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_16: /* 0x03 */
+/* File: armv5te/OP_MOVE_16.S */
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(r1, 2) @ r1<- BBBB
+ FETCH(r0, 1) @ r0<- AAAA
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AAAA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_WIDE: /* 0x04 */
+/* File: armv6t2/OP_MOVE_WIDE.S */
+ /* move-wide vA, vB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[B]
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[A]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_WIDE_FROM16: /* 0x05 */
+/* File: armv5te/OP_MOVE_WIDE_FROM16.S */
+ /* move-wide/from16 vAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ FETCH(r3, 1) @ r3<- BBBB
+ mov r2, rINST, lsr #8 @ r2<- AA
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[AA]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_WIDE_16: /* 0x06 */
+/* File: armv5te/OP_MOVE_WIDE_16.S */
+ /* move-wide/16 vAAAA, vBBBB */
+ /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
+ FETCH(r3, 2) @ r3<- BBBB
+ FETCH(r2, 1) @ r2<- AAAA
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BBBB]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AAAA]
+ ldmia r3, {r0-r1} @ r0/r1<- fp[BBBB]
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[AAAA]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_OBJECT: /* 0x07 */
+/* File: armv5te/OP_MOVE_OBJECT.S */
+/* File: armv5te/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ mov r0, rINST, lsr #8 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ and r0, r0, #15
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r2, r0) @ fp[A]<- r2
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_OBJECT_FROM16: /* 0x08 */
+/* File: armv5te/OP_MOVE_OBJECT_FROM16.S */
+/* File: armv5te/OP_MOVE_FROM16.S */
+ /* for: move/from16, move-object/from16 */
+ /* op vAA, vBBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ mov r0, rINST, lsr #8 @ r0<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_OBJECT_16: /* 0x09 */
+/* File: armv5te/OP_MOVE_OBJECT_16.S */
+/* File: armv5te/OP_MOVE_16.S */
+ /* for: move/16, move-object/16 */
+ /* op vAAAA, vBBBB */
+ FETCH(r1, 2) @ r1<- BBBB
+ FETCH(r0, 1) @ r0<- AAAA
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[BBBB]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r0) @ fp[AAAA]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_RESULT: /* 0x0a */
+/* File: armv5te/OP_MOVE_RESULT.S */
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- glue->retval.i
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[AA]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_RESULT_WIDE: /* 0x0b */
+/* File: armv5te/OP_MOVE_RESULT_WIDE.S */
+ /* move-result-wide vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ add r3, rGLUE, #offGlue_retval @ r3<- &glue->retval
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
+ ldmia r3, {r0-r1} @ r0/r1<- retval.j
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r2, {r0-r1} @ fp[AA]<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_RESULT_OBJECT: /* 0x0c */
+/* File: armv5te/OP_MOVE_RESULT_OBJECT.S */
+/* File: armv5te/OP_MOVE_RESULT.S */
+ /* for: move-result, move-result-object */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r0, [rGLUE, #offGlue_retval] @ r0<- glue->retval.i
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[AA]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MOVE_EXCEPTION: /* 0x0d */
+/* File: armv5te/OP_MOVE_EXCEPTION.S */
+ /* move-exception vAA */
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ mov r2, rINST, lsr #8 @ r2<- AA
+ ldr r3, [r0, #offThread_exception] @ r3<- dvmGetException bypass
+ mov r1, #0 @ r1<- 0
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ SET_VREG(r3, r2) @ fp[AA]<- exception obj
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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 */
+/* File: armv5te/OP_RETURN.S */
+ /*
+ * Return a 32-bit value. Copies the return value into the "glue"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r0, r2) @ r0<- vAA
+ str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RETURN_WIDE: /* 0x10 */
+/* File: armv5te/OP_RETURN_WIDE.S */
+ /*
+ * Return a 64-bit value. Copies the return value into the "glue"
+ * structure, then jumps to the return handler.
+ */
+ /* return-wide vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[AA]
+ add r3, rGLUE, #offGlue_retval @ r3<- &glue->retval
+ ldmia r2, {r0-r1} @ r0/r1 <- vAA/vAA+1
+ stmia r3, {r0-r1} @ retval<- r0/r1
+ b common_returnFromMethod
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RETURN_OBJECT: /* 0x11 */
+/* File: armv5te/OP_RETURN_OBJECT.S */
+/* File: armv5te/OP_RETURN.S */
+ /*
+ * Return a 32-bit value. Copies the return value into the "glue"
+ * structure, then jumps to the return handler.
+ *
+ * for: return, return-object
+ */
+ /* op vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r0, r2) @ r0<- vAA
+ str r0, [rGLUE, #offGlue_retval] @ retval.i <- vAA
+ b common_returnFromMethod
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_4: /* 0x12 */
+/* File: armv6t2/OP_CONST_4.S */
+ /* const/4 vA, #+B */
+ mov r1, rINST, lsl #16 @ r1<- Bxxx0000
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r1, r1, asr #28 @ r1<- sssssssB (sign-extended)
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r1, r0) @ fp[A]<- r1
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_16: /* 0x13 */
+/* File: armv5te/OP_CONST_16.S */
+ /* const/16 vAA, #+BBBB */
+ FETCH_S(r0, 1) @ r0<- ssssBBBB (sign-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST: /* 0x14 */
+/* File: armv5te/OP_CONST.S */
+ /* const vAA, #+BBBBbbbb */
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH(r0, 1) @ r0<- bbbb (low)
+ FETCH(r1, 2) @ r1<- BBBB (high)
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_HIGH16: /* 0x15 */
+/* File: armv5te/OP_CONST_HIGH16.S */
+ /* const/high16 vAA, #+BBBB0000 */
+ FETCH(r0, 1) @ r0<- 0000BBBB (zero-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ mov r0, r0, lsl #16 @ r0<- BBBB0000
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE_16: /* 0x16 */
+/* File: armv5te/OP_CONST_WIDE_16.S */
+ /* const-wide/16 vAA, #+BBBB */
+ FETCH_S(r0, 1) @ r0<- ssssBBBB (sign-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ mov r1, r0, asr #31 @ r1<- ssssssss
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE_32: /* 0x17 */
+/* File: armv5te/OP_CONST_WIDE_32.S */
+ /* const-wide/32 vAA, #+BBBBbbbb */
+ FETCH(r0, 1) @ r0<- 0000bbbb (low)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH_S(r2, 2) @ r2<- ssssBBBB (high)
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ orr r0, r0, r2, lsl #16 @ r0<- BBBBbbbb
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
+ mov r1, r0, asr #31 @ r1<- ssssssss
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE: /* 0x18 */
+/* File: armv5te/OP_CONST_WIDE.S */
+ /* const-wide vAA, #+HHHHhhhhBBBBbbbb */
+ FETCH(r0, 1) @ r0<- bbbb (low)
+ FETCH(r1, 2) @ r1<- BBBB (low middle)
+ FETCH(r2, 3) @ r2<- hhhh (high middle)
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb (low word)
+ FETCH(r3, 4) @ r3<- HHHH (high)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ orr r1, r2, r3, lsl #16 @ r1<- HHHHhhhh (high word)
+ FETCH_ADVANCE_INST(5) @ advance rPC, load rINST
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_WIDE_HIGH16: /* 0x19 */
+/* File: armv5te/OP_CONST_WIDE_HIGH16.S */
+ /* const-wide/high16 vAA, #+BBBB000000000000 */
+ FETCH(r1, 1) @ r1<- 0000BBBB (zero-extended)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ mov r0, #0 @ r0<- 00000000
+ mov r1, r1, lsl #16 @ r1<- BBBB0000
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r3, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_STRING: /* 0x1a */
+/* File: armv5te/OP_CONST_STRING.S */
+ /* const/string vAA, String@BBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r2, #offDvmDex_pResStrings] @ r2<- dvmDex->pResStrings
+ ldr r0, [r2, r1, lsl #2] @ r0<- pResStrings[BBBB]
+ cmp r0, #0 @ not yet resolved?
+ beq .LOP_CONST_STRING_resolve
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_STRING_JUMBO: /* 0x1b */
+/* File: armv5te/OP_CONST_STRING_JUMBO.S */
+ /* const/string vAA, String@BBBBBBBB */
+ FETCH(r0, 1) @ r0<- bbbb (low)
+ FETCH(r1, 2) @ r1<- BBBB (high)
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r2, #offDvmDex_pResStrings] @ r2<- dvmDex->pResStrings
+ orr r1, r0, r1, lsl #16 @ r1<- BBBBbbbb
+ ldr r0, [r2, r1, lsl #2] @ r0<- pResStrings[BBBB]
+ cmp r0, #0
+ beq .LOP_CONST_STRING_JUMBO_resolve
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CONST_CLASS: /* 0x1c */
+/* File: armv5te/OP_CONST_CLASS.S */
+ /* const/class vAA, Class@BBBB */
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- glue->methodClassDex
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r2, [r2, #offDvmDex_pResClasses] @ r2<- dvmDex->pResClasses
+ ldr r0, [r2, r1, lsl #2] @ r0<- pResClasses[BBBB]
+ cmp r0, #0 @ not yet resolved?
+ beq .LOP_CONST_CLASS_resolve
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MONITOR_ENTER: /* 0x1d */
+/* File: armv5te/OP_MONITOR_ENTER.S */
+ /*
+ * Synchronize on an object.
+ */
+ /* monitor-enter vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r1, r2) @ r1<- vAA (object)
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ cmp r1, #0 @ null object?
+ EXPORT_PC() @ need for precise GC, MONITOR_TRACKING
+ beq common_errNullObject @ null object, throw an exception
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ bl dvmLockObject @ call(self, obj)
+#ifdef WITH_DEADLOCK_PREDICTION /* implies WITH_MONITOR_TRACKING */
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ ldr r1, [r0, #offThread_exception] @ check for exception
+ cmp r1, #0
+ bne common_exceptionThrown @ exception raised, bail out
+#endif
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MONITOR_EXIT: /* 0x1e */
+/* File: armv5te/OP_MONITOR_EXIT.S */
+ /*
+ * Unlock an object.
+ *
+ * Exceptions that occur when unlocking a monitor need to appear as
+ * if they happened at the following instruction. See the Dalvik
+ * instruction spec.
+ */
+ /* monitor-exit vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ EXPORT_PC() @ before fetch: export the PC
+ GET_VREG(r1, r2) @ r1<- vAA (object)
+ cmp r1, #0 @ null object?
+ beq common_errNullObject @ yes
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ bl dvmUnlockObject @ r0<- success for unlock(self, obj)
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yes, exception is pending
+ FETCH_ADVANCE_INST(1) @ before throw: advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CHECK_CAST: /* 0x1f */
+/* File: armv5te/OP_CHECK_CAST.S */
+ /*
+ * Check to see if a cast from one class to another is allowed.
+ */
+ /* check-cast vAA, class@BBBB */
+ mov r3, rINST, lsr #8 @ r3<- AA
+ FETCH(r2, 1) @ r2<- BBBB
+ GET_VREG(r9, r3) @ r9<- object
+ ldr r0, [rGLUE, #offGlue_methodClassDex] @ r0<- pDvmDex
+ cmp r9, #0 @ is object null?
+ ldr r0, [r0, #offDvmDex_pResClasses] @ r0<- pDvmDex->pResClasses
+ beq .LOP_CHECK_CAST_okay @ null obj, cast always succeeds
+ ldr r1, [r0, r2, lsl #2] @ r1<- resolved class
+ ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
+ cmp r1, #0 @ have we resolved this before?
+ beq .LOP_CHECK_CAST_resolve @ not resolved, do it now
+.LOP_CHECK_CAST_resolved:
+ cmp r0, r1 @ same class (trivial success)?
+ bne .LOP_CHECK_CAST_fullcheck @ no, do full check
+.LOP_CHECK_CAST_okay:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INSTANCE_OF: /* 0x20 */
+/* File: armv5te/OP_INSTANCE_OF.S */
+ /*
+ * Check to see if an object reference is an instance of a class.
+ *
+ * Most common situation is a non-null object, being compared against
+ * an already-resolved class.
+ */
+ /* instance-of vA, vB, class@CCCC */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ GET_VREG(r0, r3) @ r0<- vB (object)
+ and r9, r9, #15 @ r9<- A
+ cmp r0, #0 @ is object null?
+ ldr r2, [rGLUE, #offGlue_methodClassDex] @ r2<- pDvmDex
+ beq .LOP_INSTANCE_OF_store @ null obj, not an instance, store r0
+ FETCH(r3, 1) @ r3<- CCCC
+ ldr r2, [r2, #offDvmDex_pResClasses] @ r2<- pDvmDex->pResClasses
+ ldr r1, [r2, r3, lsl #2] @ r1<- resolved class
+ ldr r0, [r0, #offObject_clazz] @ r0<- obj->clazz
+ cmp r1, #0 @ have we resolved this before?
+ beq .LOP_INSTANCE_OF_resolve @ not resolved, do it now
+.LOP_INSTANCE_OF_resolved: @ r0=obj->clazz, r1=resolved class
+ cmp r0, r1 @ same class (trivial success)?
+ beq .LOP_INSTANCE_OF_trivial @ yes, trivial finish
+ b .LOP_INSTANCE_OF_fullcheck @ no, do full check
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ARRAY_LENGTH: /* 0x21 */
+/* File: armv6t2/OP_ARRAY_LENGTH.S */
+ /*
+ * Return the length of an array.
+ */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ GET_VREG(r0, r1) @ r0<- vB (object ref)
+ cmp r0, #0 @ is object null?
+ beq common_errNullObject @ yup, fail
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ ldr r3, [r0, #offArrayObject_length] @ r3<- array length
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r3, r2) @ vB<- length
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEW_INSTANCE: /* 0x22 */
+/* File: armv5te/OP_NEW_INSTANCE.S */
+ /*
+ * Create a new instance of a class.
+ */
+ /* new-instance vAA, class@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
+ EXPORT_PC() @ req'd for init, resolve, alloc
+ cmp r0, #0 @ already resolved?
+ beq .LOP_NEW_INSTANCE_resolve @ no, resolve it now
+.LOP_NEW_INSTANCE_resolved: @ r0=class
+ ldrb r1, [r0, #offClassObject_status] @ r1<- ClassStatus enum
+ cmp r1, #CLASS_INITIALIZED @ has class been initialized?
+ bne .LOP_NEW_INSTANCE_needinit @ no, init class now
+.LOP_NEW_INSTANCE_initialized: @ r0=class
+ mov r1, #ALLOC_DONT_TRACK @ flags for alloc call
+ bl dvmAllocObject @ r0<- new object
+ b .LOP_NEW_INSTANCE_finish @ continue
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEW_ARRAY: /* 0x23 */
+/* File: armv5te/OP_NEW_ARRAY.S */
+ /*
+ * Allocate an array of objects, specified with the array class
+ * and a count.
+ *
+ * The verifier guarantees that this is an array class, so we don't
+ * check for it here.
+ */
+ /* new-array vA, vB, class@CCCC */
+ mov r0, rINST, lsr #12 @ r0<- B
+ FETCH(r2, 1) @ r2<- CCCC
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ GET_VREG(r1, r0) @ r1<- vB (array length)
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ cmp r1, #0 @ check length
+ ldr r0, [r3, r2, lsl #2] @ r0<- resolved class
+ bmi common_errNegativeArraySize @ negative length, bail
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ req'd for resolve, alloc
+ bne .LOP_NEW_ARRAY_finish @ resolved, continue
+ b .LOP_NEW_ARRAY_resolve @ do resolve now
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FILLED_NEW_ARRAY: /* 0x24 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ EXPORT_PC() @ need for resolve and alloc
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
+ mov r10, rINST, lsr #8 @ r10<- AA or BA
+ cmp r0, #0 @ already resolved?
+ bne .LOP_FILLED_NEW_ARRAY_continue @ yes, continue on
+8: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- call(clazz, ref)
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ b .LOP_FILLED_NEW_ARRAY_continue
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FILLED_NEW_ARRAY_RANGE: /* 0x25 */
+/* File: armv5te/OP_FILLED_NEW_ARRAY_RANGE.S */
+/* File: armv5te/OP_FILLED_NEW_ARRAY.S */
+ /*
+ * Create a new array with elements filled from registers.
+ *
+ * for: filled-new-array, filled-new-array/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, type@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResClasses] @ r3<- pDvmDex->pResClasses
+ EXPORT_PC() @ need for resolve and alloc
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved class
+ mov r10, rINST, lsr #8 @ r10<- AA or BA
+ cmp r0, #0 @ already resolved?
+ bne .LOP_FILLED_NEW_ARRAY_RANGE_continue @ yes, continue on
+8: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- call(clazz, ref)
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ b .LOP_FILLED_NEW_ARRAY_RANGE_continue
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FILL_ARRAY_DATA: /* 0x26 */
+/* File: armv5te/OP_FILL_ARRAY_DATA.S */
+ /* fill-array-data vAA, +BBBBBBBB */
+ FETCH(r0, 1) @ r0<- bbbb (lo)
+ FETCH(r1, 2) @ r1<- BBBB (hi)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ orr r1, r0, r1, lsl #16 @ r1<- BBBBbbbb
+ GET_VREG(r0, r3) @ r0<- vAA (array object)
+ add r1, rPC, r1, lsl #1 @ r1<- PC + BBBBbbbb*2 (array data off.)
+ EXPORT_PC();
+ bl dvmInterpHandleFillArrayData@ fill the array with predefined data
+ cmp r0, #0 @ 0 means an exception is thrown
+ beq common_exceptionThrown @ has exception
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_THROW: /* 0x27 */
+/* File: armv5te/OP_THROW.S */
+ /*
+ * Throw an exception object in the current thread.
+ */
+ /* throw vAA */
+ mov r2, rINST, lsr #8 @ r2<- AA
+ GET_VREG(r1, r2) @ r1<- vAA (exception object)
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ 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 */
+/* File: armv5te/OP_GOTO.S */
+ /*
+ * Unconditional branch, 8-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto +AA */
+ mov r0, rINST, lsl #16 @ r0<- AAxx0000
+ movs r9, r0, asr #24 @ r9<- ssssssAA (sign-extended)
+ mov r9, r9, lsl #1 @ r9<- byte offset
+ bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_GOTO_16: /* 0x29 */
+/* File: armv5te/OP_GOTO_16.S */
+ /*
+ * Unconditional branch, 16-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ */
+ /* goto/16 +AAAA */
+ FETCH_S(r0, 1) @ r0<- ssssAAAA (sign-extended)
+ movs r9, r0, asl #1 @ r9<- byte offset, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_GOTO_32: /* 0x2a */
+/* File: armv5te/OP_GOTO_32.S */
+ /*
+ * Unconditional branch, 32-bit offset.
+ *
+ * The branch distance is a signed code-unit offset, which we need to
+ * double to get a byte offset.
+ *
+ * Unlike most opcodes, this one is allowed to branch to itself, so
+ * our "backward branch" test must be "<=0" instead of "<0". The ORRS
+ * instruction doesn't affect the V flag, so we need to clear it
+ * explicitly.
+ */
+ /* goto/32 +AAAAAAAA */
+ FETCH(r0, 1) @ r0<- aaaa (lo)
+ FETCH(r1, 2) @ r1<- AAAA (hi)
+ cmp ip, ip @ (clear V flag during stall)
+ orrs r0, r0, r1, lsl #16 @ r0<- AAAAaaaa, check sign
+ mov r9, r0, asl #1 @ r9<- byte offset
+ ble common_backwardBranch @ backward branch, do periodic checks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_PACKED_SWITCH: /* 0x2b */
+/* File: armv5te/OP_PACKED_SWITCH.S */
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(r0, 1) @ r0<- bbbb (lo)
+ FETCH(r1, 2) @ r1<- BBBB (hi)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
+ GET_VREG(r1, r3) @ r1<- vAA
+ add r0, rPC, r0, lsl #1 @ r0<- PC + BBBBbbbb*2
+ bl dvmInterpHandlePackedSwitch @ r0<- code-unit branch offset
+ movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+ beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPARSE_SWITCH: /* 0x2c */
+/* File: armv5te/OP_SPARSE_SWITCH.S */
+/* File: armv5te/OP_PACKED_SWITCH.S */
+ /*
+ * Handle a packed-switch or sparse-switch instruction. In both cases
+ * we decode it and hand it off to a helper function.
+ *
+ * We don't really expect backward branches in a switch statement, but
+ * they're perfectly legal, so we check for them here.
+ *
+ * for: packed-switch, sparse-switch
+ */
+ /* op vAA, +BBBB */
+ FETCH(r0, 1) @ r0<- bbbb (lo)
+ FETCH(r1, 2) @ r1<- BBBB (hi)
+ mov r3, rINST, lsr #8 @ r3<- AA
+ orr r0, r0, r1, lsl #16 @ r0<- BBBBbbbb
+ GET_VREG(r1, r3) @ r1<- vAA
+ add r0, rPC, r0, lsl #1 @ r0<- PC + BBBBbbbb*2
+ bl dvmInterpHandleSparseSwitch @ r0<- code-unit branch offset
+ movs r9, r0, asl #1 @ r9<- branch byte offset, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+ beq common_backwardBranch @ (want to use BLE but V is unknown)
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPL_FLOAT: /* 0x2d */
+/* File: arm-vfp/OP_CMPL_FLOAT.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ flds s0, [r2] @ s0<- vBB
+ flds s1, [r3] @ s1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mvn r0, #0 @ r0<- -1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r1<- 1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPL_FLOAT_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPG_FLOAT: /* 0x2e */
+/* File: arm-vfp/OP_CMPG_FLOAT.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ flds s0, [r2] @ s0<- vBB
+ flds s1, [r3] @ s1<- vCC
+ fcmpes s0, s1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mov r0, #1 @ r0<- 1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPG_FLOAT_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPL_DOUBLE: /* 0x2f */
+/* File: arm-vfp/OP_CMPL_DOUBLE.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x > y) {
+ * return 1;
+ * } else if (x < y) {
+ * return -1;
+ * } else {
+ * return -1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ fldd d0, [r2] @ d0<- vBB
+ fldd d1, [r3] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mvn r0, #0 @ r0<- -1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ movgt r0, #1 @ (greater than) r1<- 1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPL_DOUBLE_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMPG_DOUBLE: /* 0x30 */
+/* File: arm-vfp/OP_CMPG_DOUBLE.S */
+ /*
+ * Compare two floating-point values. Puts 0, 1, or -1 into the
+ * destination register based on the results of the comparison.
+ *
+ * int compare(x, y) {
+ * if (x == y) {
+ * return 0;
+ * } else if (x < y) {
+ * return -1;
+ * } else if (x > y) {
+ * return 1;
+ * } else {
+ * return 1;
+ * }
+ * }
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ fldd d0, [r2] @ d0<- vBB
+ fldd d1, [r3] @ d1<- vCC
+ fcmped d0, d1 @ compare (vBB, vCC)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ mov r0, #1 @ r0<- 1 (default)
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fmstat @ export status flags
+ mvnmi r0, #0 @ (less than) r1<- -1
+ moveq r0, #0 @ (equal) r1<- 0
+ b .LOP_CMPG_DOUBLE_finish @ argh
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_CMP_LONG: /* 0x31 */
+/* File: armv5te/OP_CMP_LONG.S */
+ /*
+ * Compare two 64-bit values. Puts 0, 1, or -1 into the destination
+ * register based on the results of the comparison.
+ *
+ * We load the full values with LDM, but in practice many values could
+ * be resolved by only looking at the high word. This could be made
+ * faster or slower by splitting the LDM into a pair of LDRs.
+ *
+ * If we just wanted to set condition flags, we could do this:
+ * subs ip, r0, r2
+ * sbcs ip, r1, r3
+ * subeqs ip, r0, r2
+ * Leaving { <0, 0, >0 } in ip. However, we have to set it to a specific
+ * integer value, which we can do with 2 conditional mov/mvn instructions
+ * (set 1, set -1; if they're equal we already have 0 in ip), giving
+ * us a constant 5-cycle path plus a branch at the end to the
+ * instruction epilogue code. The multi-compare approach below needs
+ * 2 or 3 cycles + branch if the high word doesn't match, 6 + branch
+ * in the worst case (the 64-bit values are equal).
+ */
+ /* cmp-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ cmp r1, r3 @ compare (vBB+1, vCC+1)
+ blt .LOP_CMP_LONG_less @ signed compare on high part
+ bgt .LOP_CMP_LONG_greater
+ subs r1, r0, r2 @ r1<- r0 - r2
+ bhi .LOP_CMP_LONG_greater @ unsigned compare on low part
+ bne .LOP_CMP_LONG_less
+ b .LOP_CMP_LONG_finish @ equal; r1 already holds 0
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_EQ: /* 0x32 */
+/* File: armv6t2/OP_IF_EQ.S */
+/* File: armv6t2/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ bne 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_NE: /* 0x33 */
+/* File: armv6t2/OP_IF_NE.S */
+/* File: armv6t2/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ beq 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LT: /* 0x34 */
+/* File: armv6t2/OP_IF_LT.S */
+/* File: armv6t2/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ bge 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GE: /* 0x35 */
+/* File: armv6t2/OP_IF_GE.S */
+/* File: armv6t2/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ blt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GT: /* 0x36 */
+/* File: armv6t2/OP_IF_GT.S */
+/* File: armv6t2/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ ble 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LE: /* 0x37 */
+/* File: armv6t2/OP_IF_LE.S */
+/* File: armv6t2/bincmp.S */
+ /*
+ * Generic two-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * For: if-eq, if-ne, if-lt, if-ge, if-gt, if-le
+ */
+ /* if-cmp vA, vB, +CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r3, r1) @ r3<- vB
+ GET_VREG(r2, r0) @ r2<- vA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, r3 @ compare (vA, vB)
+ bgt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ yes, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ b common_testUpdateProfile
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_EQZ: /* 0x38 */
+/* File: armv5te/OP_IF_EQZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ bne 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_NEZ: /* 0x39 */
+/* File: armv5te/OP_IF_NEZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ beq 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LTZ: /* 0x3a */
+/* File: armv5te/OP_IF_LTZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ bge 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GEZ: /* 0x3b */
+/* File: armv5te/OP_IF_GEZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ blt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_GTZ: /* 0x3c */
+/* File: armv5te/OP_IF_GTZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ ble 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IF_LEZ: /* 0x3d */
+/* File: armv5te/OP_IF_LEZ.S */
+/* File: armv5te/zcmp.S */
+ /*
+ * Generic one-operand compare-and-branch operation. Provide a "revcmp"
+ * fragment that specifies the *reverse* comparison to perform, e.g.
+ * for "if-le" you would use "gt".
+ *
+ * for: if-eqz, if-nez, if-ltz, if-gez, if-gtz, if-lez
+ */
+ /* if-cmp vAA, +BBBB */
+ mov r0, rINST, lsr #8 @ r0<- AA
+ GET_VREG(r2, r0) @ r2<- vAA
+ mov r9, #4 @ r0<- BYTE branch dist for not-taken
+ cmp r2, #0 @ compare (vA, 0)
+ bgt 1f @ branch to 1 if comparison failed
+ FETCH_S(r9, 1) @ r9<- branch offset, in code units
+ movs r9, r9, asl #1 @ convert to bytes, check sign
+ bmi common_backwardBranch @ backward branch, do periodic checks
+1:
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_3E: /* 0x3e */
+/* File: armv5te/OP_UNUSED_3E.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_3F: /* 0x3f */
+/* File: armv5te/OP_UNUSED_3F.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_40: /* 0x40 */
+/* File: armv5te/OP_UNUSED_40.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_41: /* 0x41 */
+/* File: armv5te/OP_UNUSED_41.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_42: /* 0x42 */
+/* File: armv5te/OP_UNUSED_42.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_43: /* 0x43 */
+/* File: armv5te/OP_UNUSED_43.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET: /* 0x44 */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_WIDE: /* 0x45 */
+/* File: armv5te/OP_AGET_WIDE.S */
+ /*
+ * Array get, 64 bits. vAA <- vBB[vCC].
+ *
+ * Arrays of long/double are 64-bit aligned, so it's okay to use LDRD.
+ */
+ /* aget-wide vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #3 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcc .LOP_AGET_WIDE_finish @ okay, continue below
+ b common_errArrayIndex @ index >= length, bail
+ @ May want to swap the order of these two branches depending on how the
+ @ branch prediction (if any) handles conditional forward branches vs.
+ @ unconditional forward branches.
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_OBJECT: /* 0x46 */
+/* File: armv5te/OP_AGET_OBJECT.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldr r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_BOOLEAN: /* 0x47 */
+/* File: armv5te/OP_AGET_BOOLEAN.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrb r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_BYTE: /* 0x48 */
+/* File: armv5te/OP_AGET_BYTE.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrsb r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_CHAR: /* 0x49 */
+/* File: armv5te/OP_AGET_CHAR.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrh r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AGET_SHORT: /* 0x4a */
+/* File: armv5te/OP_AGET_SHORT.S */
+/* File: armv5te/OP_AGET.S */
+ /*
+ * Array get, 32 bits or less. vAA <- vBB[vCC].
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aget, aget-object, aget-boolean, aget-byte, aget-char, aget-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrsh r2, [r0, #offArrayObject_contents] @ r2<- vBB[vCC]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r2, r9) @ vAA<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT: /* 0x4b */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #2 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ str r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_WIDE: /* 0x4c */
+/* File: armv5te/OP_APUT_WIDE.S */
+ /*
+ * Array put, 64 bits. vBB[vCC] <- vAA.
+ *
+ * Arrays of long/double are 64-bit aligned, so it's okay to use STRD.
+ */
+ /* aput-wide vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #3 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ bcc .LOP_APUT_WIDE_finish @ okay, continue below
+ b common_errArrayIndex @ index >= length, bail
+ @ May want to swap the order of these two branches depending on how the
+ @ branch prediction (if any) handles conditional forward branches vs.
+ @ unconditional forward branches.
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_OBJECT: /* 0x4d */
+/* File: armv5te/OP_APUT_OBJECT.S */
+ /*
+ * Store an object into an array. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ */
+ /* op vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ GET_VREG(r1, r2) @ r1<- vBB (array object)
+ GET_VREG(r0, r3) @ r0<- vCC (requested index)
+ cmp r1, #0 @ null array object?
+ GET_VREG(r9, r9) @ r9<- vAA
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r1, #offArrayObject_length] @ r3<- arrayObj->length
+ add r10, r1, r0, lsl #2 @ r10<- arrayObj + index*width
+ cmp r0, r3 @ compare unsigned index, length
+ bcc .LOP_APUT_OBJECT_finish @ we're okay, continue on
+ b common_errArrayIndex @ index >= length, bail
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_BOOLEAN: /* 0x4e */
+/* File: armv5te/OP_APUT_BOOLEAN.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strb r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_BYTE: /* 0x4f */
+/* File: armv5te/OP_APUT_BYTE.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #0 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strb r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_CHAR: /* 0x50 */
+/* File: armv5te/OP_APUT_CHAR.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strh r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_APUT_SHORT: /* 0x51 */
+/* File: armv5te/OP_APUT_SHORT.S */
+/* File: armv5te/OP_APUT.S */
+ /*
+ * Array put, 32 bits or less. vBB[vCC] <- vAA.
+ *
+ * Note: using the usual FETCH/and/shift stuff, this fits in exactly 17
+ * instructions. We use a pair of FETCH_Bs instead.
+ *
+ * for: aput, aput-boolean, aput-byte, aput-char, aput-short
+ */
+ /* op vAA, vBB, vCC */
+ FETCH_B(r2, 1, 0) @ r2<- BB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ FETCH_B(r3, 1, 1) @ r3<- CC
+ GET_VREG(r0, r2) @ r0<- vBB (array object)
+ GET_VREG(r1, r3) @ r1<- vCC (requested index)
+ cmp r0, #0 @ null array object?
+ beq common_errNullObject @ yes, bail
+ ldr r3, [r0, #offArrayObject_length] @ r3<- arrayObj->length
+ add r0, r0, r1, lsl #1 @ r0<- arrayObj + index*width
+ cmp r1, r3 @ compare unsigned index, length
+ bcs common_errArrayIndex @ index >= length, bail
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_VREG(r2, r9) @ r2<- vAA
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ strh r2, [r0, #offArrayObject_contents] @ vBB[vCC]<- r2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET: /* 0x52 */
+/* File: armv6t2/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_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_finish
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_WIDE: /* 0x53 */
+/* File: armv6t2/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_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_finish
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_OBJECT: /* 0x54 */
+/* File: armv5te/OP_IGET_OBJECT.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_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_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_BOOLEAN: /* 0x55 */
+/* File: armv5te/OP_IGET_BOOLEAN.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrb", "sqnum":"1" }
+/* 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_BOOLEAN_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_BOOLEAN_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_BYTE: /* 0x56 */
+/* File: armv5te/OP_IGET_BYTE.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrsb", "sqnum":"2" }
+/* 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_BYTE_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_BYTE_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_CHAR: /* 0x57 */
+/* File: armv5te/OP_IGET_CHAR.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrh", "sqnum":"3" }
+/* 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_CHAR_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_CHAR_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_SHORT: /* 0x58 */
+/* File: armv5te/OP_IGET_SHORT.S */
+@include "armv5te/OP_IGET.S" { "load":"ldrsh", "sqnum":"4" }
+/* 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_SHORT_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_SHORT_finish
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT: /* 0x59 */
+/* File: armv6t2/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 */
+ 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_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_finish @ yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_WIDE: /* 0x5a */
+/* File: armv6t2/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_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_finish @ yes, finish up
+ b common_exceptionThrown
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_OBJECT: /* 0x5b */
+/* File: armv5te/OP_IPUT_OBJECT.S */
+/* File: armv5te/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 */
+ 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_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_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_BOOLEAN: /* 0x5c */
+/* File: armv5te/OP_IPUT_BOOLEAN.S */
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"1" }
+/* File: armv5te/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 */
+ 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_BOOLEAN_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_BOOLEAN_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_BYTE: /* 0x5d */
+/* File: armv5te/OP_IPUT_BYTE.S */
+@include "armv5te/OP_IPUT.S" { "store":"strb", "sqnum":"2" }
+/* File: armv5te/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 */
+ 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_BYTE_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_BYTE_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_CHAR: /* 0x5e */
+/* File: armv5te/OP_IPUT_CHAR.S */
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"3" }
+/* File: armv5te/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 */
+ 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_CHAR_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_CHAR_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_SHORT: /* 0x5f */
+/* File: armv5te/OP_IPUT_SHORT.S */
+@include "armv5te/OP_IPUT.S" { "store":"strh", "sqnum":"4" }
+/* File: armv5te/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 */
+ 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_SHORT_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_SHORT_finish @ yes, finish up
+ b common_exceptionThrown
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SGET: /* 0x60 */
+/* 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_resolve @ yes, do resolve
+.LOP_SGET_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_WIDE: /* 0x61 */
+/* 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_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]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ stmia r1, {r2-r3} @ vAA/vAA+1<- r2/r3
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SGET_OBJECT: /* 0x62 */
+/* File: armv5te/OP_SGET_OBJECT.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_resolve @ yes, do resolve
+.LOP_SGET_OBJECT_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_BOOLEAN: /* 0x63 */
+/* File: armv5te/OP_SGET_BOOLEAN.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_BOOLEAN_resolve @ yes, do resolve
+.LOP_SGET_BOOLEAN_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_BYTE: /* 0x64 */
+/* File: armv5te/OP_SGET_BYTE.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_BYTE_resolve @ yes, do resolve
+.LOP_SGET_BYTE_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_CHAR: /* 0x65 */
+/* File: armv5te/OP_SGET_CHAR.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_CHAR_resolve @ yes, do resolve
+.LOP_SGET_CHAR_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SGET_SHORT: /* 0x66 */
+/* File: armv5te/OP_SGET_SHORT.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_SHORT_resolve @ yes, do resolve
+.LOP_SGET_SHORT_finish: @ field ptr in r0
+ ldr r1, [r0, #offStaticField_value] @ r1<- field value
+ 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_SPUT: /* 0x67 */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_resolve @ yes, do resolve
+.LOP_SPUT_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
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_WIDE: /* 0x68 */
+/* File: armv5te/OP_SPUT_WIDE.S */
+ /*
+ * 64-bit SPUT handler.
+ */
+ /* sput-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
+ mov r9, rINST, lsr #8 @ r9<- AA
+ ldr r0, [r2, r1, lsl #2] @ r0<- resolved StaticField ptr
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ cmp r0, #0 @ is resolved entry null?
+ beq .LOP_SPUT_WIDE_resolve @ yes, do resolve
+.LOP_SPUT_WIDE_finish: @ field ptr in r0, 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
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_OBJECT: /* 0x69 */
+/* File: armv5te/OP_SPUT_OBJECT.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_BOOLEAN: /* 0x6a */
+/* File: armv5te/OP_SPUT_BOOLEAN.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_BOOLEAN_resolve @ yes, do resolve
+.LOP_SPUT_BOOLEAN_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_BYTE: /* 0x6b */
+/* File: armv5te/OP_SPUT_BYTE.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_BYTE_resolve @ yes, do resolve
+.LOP_SPUT_BYTE_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_CHAR: /* 0x6c */
+/* File: armv5te/OP_SPUT_CHAR.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_CHAR_resolve @ yes, do resolve
+.LOP_SPUT_CHAR_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SPUT_SHORT: /* 0x6d */
+/* File: armv5te/OP_SPUT_SHORT.S */
+/* File: armv5te/OP_SPUT.S */
+ /*
+ * General 32-bit SPUT handler.
+ *
+ * for: sput, sput-object, 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_SHORT_resolve @ yes, do resolve
+.LOP_SPUT_SHORT_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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL: /* 0x6e */
+/* File: armv5te/OP_INVOKE_VIRTUAL.S */
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_VIRTUAL_continue @ yes, continue on
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_VIRTUAL_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER: /* 0x6f */
+/* File: armv5te/OP_INVOKE_SUPER.S */
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ cmp r2, #0 @ null "this"?
+ ldr r9, [rGLUE, #offGlue_method] @ r9<- current method
+ beq common_errNullObject @ null "this", throw exception
+ cmp r0, #0 @ already resolved?
+ ldr r9, [r9, #offMethod_clazz] @ r9<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_SUPER_continue @ resolved, continue on
+ b .LOP_INVOKE_SUPER_resolve @ do resolve now
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_DIRECT: /* 0x70 */
+/* File: armv5te/OP_INVOKE_DIRECT.S */
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ beq .LOP_INVOKE_DIRECT_resolve @ not resolved, do it now
+.LOP_INVOKE_DIRECT_finish:
+ cmp r2, #0 @ null "this" ref?
+ bne common_invokeMethodNoRange @ no, continue on
+ b common_errNullObject @ yes, throw exception
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_STATIC: /* 0x71 */
+/* File: armv5te/OP_INVOKE_STATIC.S */
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne common_invokeMethodNoRange @ yes, continue on
+0: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_STATIC @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne common_invokeMethodNoRange @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_INTERFACE: /* 0x72 */
+/* File: armv5te/OP_INVOKE_INTERFACE.S */
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r2, 2) @ r2<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!0)
+ and r2, r2, #15 @ r2<- C (or stays CCCC)
+ .endif
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r0, r2) @ r0<- first arg ("this")
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- methodClassDex
+ cmp r0, #0 @ null obj?
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- method
+ beq common_errNullObject @ yes, fail
+ ldr r0, [r0, #offObject_clazz] @ r0<- thisPtr->clazz
+ 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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_73: /* 0x73 */
+/* File: armv5te/OP_UNUSED_73.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL_RANGE: /* 0x74 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_RANGE.S */
+/* File: armv5te/OP_INVOKE_VIRTUAL.S */
+ /*
+ * Handle a virtual method call.
+ *
+ * for: invoke-virtual, invoke-virtual/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_VIRTUAL_RANGE_continue @ yes, continue on
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_VIRTUAL_RANGE_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER_RANGE: /* 0x75 */
+/* File: armv5te/OP_INVOKE_SUPER_RANGE.S */
+/* File: armv5te/OP_INVOKE_SUPER.S */
+ /*
+ * Handle a "super" method call.
+ *
+ * for: invoke-super, invoke-super/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved baseMethod
+ cmp r2, #0 @ null "this"?
+ ldr r9, [rGLUE, #offGlue_method] @ r9<- current method
+ beq common_errNullObject @ null "this", throw exception
+ cmp r0, #0 @ already resolved?
+ ldr r9, [r9, #offMethod_clazz] @ r9<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ bne .LOP_INVOKE_SUPER_RANGE_continue @ resolved, continue on
+ b .LOP_INVOKE_SUPER_RANGE_resolve @ do resolve now
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_DIRECT_RANGE: /* 0x76 */
+/* File: armv5te/OP_INVOKE_DIRECT_RANGE.S */
+/* File: armv5te/OP_INVOKE_DIRECT.S */
+ /*
+ * Handle a direct method call.
+ *
+ * (We could defer the "is 'this' pointer null" test to the common
+ * method invocation code, and use a flag to indicate that static
+ * calls don't count. If we do this as part of copying the arguments
+ * out we could avoiding loading the first arg twice.)
+ *
+ * for: invoke-direct, invoke-direct/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r2, r10) @ r2<- "this" ptr
+ beq .LOP_INVOKE_DIRECT_RANGE_resolve @ not resolved, do it now
+.LOP_INVOKE_DIRECT_RANGE_finish:
+ cmp r2, #0 @ null "this" ref?
+ bne common_invokeMethodRange @ no, continue on
+ b common_errNullObject @ yes, throw exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_STATIC_RANGE: /* 0x77 */
+/* File: armv5te/OP_INVOKE_STATIC_RANGE.S */
+/* File: armv5te/OP_INVOKE_STATIC.S */
+ /*
+ * Handle a static method call.
+ *
+ * for: invoke-static, invoke-static/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- pDvmDex
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r3, [r3, #offDvmDex_pResMethods] @ r3<- pDvmDex->pResMethods
+ ldr r0, [r3, r1, lsl #2] @ r0<- resolved methodToCall
+ cmp r0, #0 @ already resolved?
+ EXPORT_PC() @ must export for invoke
+ bne common_invokeMethodRange @ yes, continue on
+0: ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_STATIC @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne common_invokeMethodRange @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_INTERFACE_RANGE: /* 0x78 */
+/* File: armv5te/OP_INVOKE_INTERFACE_RANGE.S */
+/* File: armv5te/OP_INVOKE_INTERFACE.S */
+ /*
+ * Handle an interface method call.
+ *
+ * for: invoke-interface, invoke-interface/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r2, 2) @ r2<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!1)
+ and r2, r2, #15 @ r2<- C (or stays CCCC)
+ .endif
+ EXPORT_PC() @ must export for invoke
+ GET_VREG(r0, r2) @ r0<- first arg ("this")
+ ldr r3, [rGLUE, #offGlue_methodClassDex] @ r3<- methodClassDex
+ cmp r0, #0 @ null obj?
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- method
+ beq common_errNullObject @ yes, fail
+ ldr r0, [r0, #offObject_clazz] @ r0<- thisPtr->clazz
+ 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
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_79: /* 0x79 */
+/* File: armv5te/OP_UNUSED_79.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_7A: /* 0x7a */
+/* File: armv5te/OP_UNUSED_7A.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_INT: /* 0x7b */
+/* File: armv6t2/OP_NEG_INT.S */
+/* File: armv6t2/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ rsb r0, r0, #0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NOT_INT: /* 0x7c */
+/* File: armv6t2/OP_NOT_INT.S */
+/* File: armv6t2/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mvn r0, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_LONG: /* 0x7d */
+/* File: armv6t2/OP_NEG_LONG.S */
+/* File: armv6t2/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ rsbs r0, r0, #0 @ optional op; may set condition codes
+ rsc r1, r1, #0 @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NOT_LONG: /* 0x7e */
+/* File: armv6t2/OP_NOT_LONG.S */
+/* File: armv6t2/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mvn r0, r0 @ optional op; may set condition codes
+ mvn r1, r1 @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_FLOAT: /* 0x7f */
+/* File: armv6t2/OP_NEG_FLOAT.S */
+/* File: armv6t2/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ add r0, r0, #0x80000000 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_NEG_DOUBLE: /* 0x80 */
+/* File: armv6t2/OP_NEG_DOUBLE.S */
+/* File: armv6t2/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ add r1, r1, #0x80000000 @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_LONG: /* 0x81 */
+/* File: armv6t2/OP_INT_TO_LONG.S */
+/* File: armv6t2/unopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0", where
+ * "result" is a 64-bit quantity in r0/r1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ mov r1, r0, asr #31 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_FLOAT: /* 0x82 */
+/* File: arm-vfp/OP_INT_TO_FLOAT.S */
+/* File: arm-vfp/funop.S */
+ /*
+ * Generic 32-bit unary floating-point operation. Provide an "instr"
+ * line that specifies an instruction that performs "s1 = op s0".
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fsitos s1, s0 @ s1<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s1, [r9] @ vA<- s1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_DOUBLE: /* 0x83 */
+/* File: arm-vfp/OP_INT_TO_DOUBLE.S */
+/* File: arm-vfp/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fsitod d0, s0 @ d0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fstd d0, [r9] @ vA<- d0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_LONG_TO_INT: /* 0x84 */
+/* File: armv5te/OP_LONG_TO_INT.S */
+/* we ignore the high word, making this equivalent to a 32-bit reg move */
+/* File: armv5te/OP_MOVE.S */
+ /* for move, move-object, long-to-int */
+ /* op vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B from 15:12
+ mov r0, rINST, lsr #8 @ r0<- A from 11:8
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ GET_VREG(r2, r1) @ r2<- fp[B]
+ and r0, r0, #15
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ SET_VREG(r2, r0) @ fp[A]<- r2
+ GOTO_OPCODE(ip) @ execute next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_LONG_TO_FLOAT: /* 0x85 */
+/* File: armv6t2/OP_LONG_TO_FLOAT.S */
+/* File: armv6t2/unopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0/r1", where
+ * "result" is a 32-bit quantity in r0.
+ *
+ * For: long-to-float, double-to-int, double-to-float
+ *
+ * (This would work for long-to-int, but that instruction is actually
+ * an exact match for OP_MOVE.)
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ ldmia r3, {r0-r1} @ r0/r1<- vB/vB+1
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_l2f @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_LONG_TO_DOUBLE: /* 0x86 */
+/* File: armv6t2/OP_LONG_TO_DOUBLE.S */
+/* File: armv6t2/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_l2d @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FLOAT_TO_INT: /* 0x87 */
+/* File: arm-vfp/OP_FLOAT_TO_INT.S */
+/* File: arm-vfp/funop.S */
+ /*
+ * Generic 32-bit unary floating-point operation. Provide an "instr"
+ * line that specifies an instruction that performs "s1 = op s0".
+ *
+ * for: int-to-float, float-to-int
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ ftosizs s1, s0 @ s1<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s1, [r9] @ vA<- s1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FLOAT_TO_LONG: /* 0x88 */
+/* File: armv6t2/OP_FLOAT_TO_LONG.S */
+@include "armv6t2/unopWider.S" {"instr":"bl __aeabi_f2lz"}
+/* File: armv6t2/unopWider.S */
+ /*
+ * Generic 32bit-to-64bit unary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = op r0", where
+ * "result" is a 64-bit quantity in r0/r1.
+ *
+ * For: int-to-long, int-to-double, float-to-long, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ bl f2l_doconv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vA/vA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 9-10 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_FLOAT_TO_DOUBLE: /* 0x89 */
+/* File: arm-vfp/OP_FLOAT_TO_DOUBLE.S */
+/* File: arm-vfp/funopWider.S */
+ /*
+ * Generic 32bit-to-64bit floating point unary operation. Provide an
+ * "instr" line that specifies an instruction that performs "d0 = op s0".
+ *
+ * For: int-to-double, float-to-double
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ flds s0, [r3] @ s0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fcvtds d0, s0 @ d0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fstd d0, [r9] @ vA<- d0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DOUBLE_TO_INT: /* 0x8a */
+/* File: arm-vfp/OP_DOUBLE_TO_INT.S */
+/* File: arm-vfp/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary floating point operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ fldd d0, [r3] @ d0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ ftosizd s0, d0 @ s0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s0, [r9] @ vA<- s0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DOUBLE_TO_LONG: /* 0x8b */
+/* File: armv6t2/OP_DOUBLE_TO_LONG.S */
+@include "armv6t2/unopWide.S" {"instr":"bl __aeabi_d2lz"}
+/* File: armv6t2/unopWide.S */
+ /*
+ * Generic 64-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0/r1".
+ * This could be an ARM instruction or a function call.
+ *
+ * For: neg-long, not-long, neg-double, long-to-double, double-to-long
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r3, {r0-r1} @ r0/r1<- vAA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl d2l_doconv @ r0/r1<- op, r2-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-11 instructions */
+
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DOUBLE_TO_FLOAT: /* 0x8c */
+/* File: arm-vfp/OP_DOUBLE_TO_FLOAT.S */
+/* File: arm-vfp/funopNarrower.S */
+ /*
+ * Generic 64bit-to-32bit unary floating point operation. Provide an
+ * "instr" line that specifies an instruction that performs "s0 = op d0".
+ *
+ * For: double-to-int, double-to-float
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ fldd d0, [r3] @ d0<- vB
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ and r9, r9, #15 @ r9<- A
+ fcvtsd s0, d0 @ s0<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ fsts s0, [r9] @ vA<- s0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_BYTE: /* 0x8d */
+/* File: armv6t2/OP_INT_TO_BYTE.S */
+/* File: armv6t2/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ sxtb r0, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_CHAR: /* 0x8e */
+/* File: armv6t2/OP_INT_TO_CHAR.S */
+/* File: armv6t2/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ uxth r0, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INT_TO_SHORT: /* 0x8f */
+/* File: armv6t2/OP_INT_TO_SHORT.S */
+/* File: armv6t2/unop.S */
+ /*
+ * Generic 32-bit unary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = op r0".
+ * This could be an ARM instruction or a function call.
+ *
+ * for: neg-int, not-int, neg-float, int-to-float, float-to-int,
+ * int-to-byte, int-to-char, int-to-short
+ */
+ /* unop vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r3) @ r0<- vB
+ @ optional op; may set condition codes
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ sxth r0, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 8-9 instructions */
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT: /* 0x90 */
+/* File: armv5te/OP_ADD_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_INT: /* 0x91 */
+/* File: armv5te/OP_SUB_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ sub r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT: /* 0x92 */
+/* File: armv5te/OP_MUL_INT.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT: /* 0x93 */
+/* File: armv5te/OP_DIV_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT: /* 0x94 */
+/* File: armv5te/OP_REM_INT.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT: /* 0x95 */
+/* File: armv5te/OP_AND_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT: /* 0x96 */
+/* File: armv5te/OP_OR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT: /* 0x97 */
+/* File: armv5te/OP_XOR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_INT: /* 0x98 */
+/* File: armv5te/OP_SHL_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_INT: /* 0x99 */
+/* File: armv5te/OP_SHR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_INT: /* 0x9a */
+/* File: armv5te/OP_USHR_INT.S */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_LONG: /* 0x9b */
+/* File: armv5te/OP_ADD_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ adds r0, r0, r2 @ optional op; may set condition codes
+ adc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_LONG: /* 0x9c */
+/* File: armv5te/OP_SUB_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ subs r0, r0, r2 @ optional op; may set condition codes
+ sbc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_LONG: /* 0x9d */
+/* File: armv5te/OP_MUL_LONG.S */
+ /*
+ * Signed 64-bit integer multiply.
+ *
+ * Consider WXxYZ (r1r0 x r3r2) with a long multiply:
+ * WX
+ * x YZ
+ * --------
+ * ZW ZX
+ * YW YX
+ *
+ * The low word of the result holds ZX, the high word holds
+ * (ZW+YX) + (the high overflow from ZX). YW doesn't matter because
+ * it doesn't fit in the low 64 bits.
+ *
+ * Unlike most ARM math operations, multiply instructions have
+ * restrictions on using the same register more than once (Rd and Rm
+ * cannot be the same).
+ */
+ /* mul-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ mov r0, rINST, lsr #8 @ r0<- AA
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ add r0, rFP, r0, lsl #2 @ r0<- &fp[AA]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_MUL_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_LONG: /* 0x9e */
+/* File: armv5te/OP_DIV_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_LONG: /* 0x9f */
+/* File: armv5te/OP_REM_LONG.S */
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r2,r3} @ vAA/vAA+1<- r2/r3
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_LONG: /* 0xa0 */
+/* File: armv5te/OP_AND_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r0, r0, r2 @ optional op; may set condition codes
+ and r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_LONG: /* 0xa1 */
+/* File: armv5te/OP_OR_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ orr r0, r0, r2 @ optional op; may set condition codes
+ orr r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_LONG: /* 0xa2 */
+/* File: armv5te/OP_XOR_LONG.S */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ eor r0, r0, r2 @ optional op; may set condition codes
+ eor r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_LONG: /* 0xa3 */
+/* File: armv5te/OP_SHL_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shl-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r3, r0, #255 @ r3<- BB
+ mov r0, r0, lsr #8 @ r0<- CC
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
+ GET_VREG(r2, r0) @ r2<- vCC
+ ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_SHL_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_LONG: /* 0xa4 */
+/* File: armv5te/OP_SHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* shr-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r3, r0, #255 @ r3<- BB
+ mov r0, r0, lsr #8 @ r0<- CC
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
+ GET_VREG(r2, r0) @ r2<- vCC
+ ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_SHR_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_LONG: /* 0xa5 */
+/* File: armv5te/OP_USHR_LONG.S */
+ /*
+ * Long integer shift. This is different from the generic 32/64-bit
+ * binary operations because vAA/vBB are 64-bit but vCC (the shift
+ * distance) is 32-bit. Also, Dalvik requires us to mask off the low
+ * 6 bits of the shift distance.
+ */
+ /* ushr-long vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r3, r0, #255 @ r3<- BB
+ mov r0, r0, lsr #8 @ r0<- CC
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[BB]
+ GET_VREG(r2, r0) @ r2<- vCC
+ ldmia r3, {r0-r1} @ r0/r1<- vBB/vBB+1
+ and r2, r2, #63 @ r0<- r0 & 0x3f
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ b .LOP_USHR_LONG_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_FLOAT: /* 0xa6 */
+/* File: arm-vfp/OP_ADD_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fadds s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_FLOAT: /* 0xa7 */
+/* File: arm-vfp/OP_SUB_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fsubs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_FLOAT: /* 0xa8 */
+/* File: arm-vfp/OP_MUL_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fmuls s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_FLOAT: /* 0xa9 */
+/* File: arm-vfp/OP_DIV_FLOAT.S */
+/* File: arm-vfp/fbinop.S */
+ /*
+ * Generic 32-bit floating-point operation. Provide an "instr" line that
+ * specifies an instruction that performs "s2 = s0 op s1". Because we
+ * use the "softfp" ABI, this must be an instruction, not a function call.
+ *
+ * For: add-float, sub-float, mul-float, div-float
+ */
+ /* floatop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ flds s1, [r3] @ s1<- vCC
+ flds s0, [r2] @ s0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fdivs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_FLOAT: /* 0xaa */
+/* File: armv5te/OP_REM_FLOAT.S */
+/* EABI doesn't define a float remainder function, but libm does */
+/* File: armv5te/binop.S */
+ /*
+ * Generic 32-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus. Note that we
+ * *don't* check for (INT_MIN / -1) here, because the ARM math lib
+ * handles it correctly.
+ *
+ * For: add-int, sub-int, mul-int, div-int, rem-int, and-int, or-int,
+ * xor-int, shl-int, shr-int, ushr-int, add-float, sub-float,
+ * mul-float, div-float, rem-float
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ GET_VREG(r1, r3) @ r1<- vCC
+ GET_VREG(r0, r2) @ r0<- vBB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ @ optional op; may set condition codes
+ bl fmodf @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 11-14 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_DOUBLE: /* 0xab */
+/* File: arm-vfp/OP_ADD_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ faddd d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_DOUBLE: /* 0xac */
+/* File: arm-vfp/OP_SUB_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fsubd d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_DOUBLE: /* 0xad */
+/* File: arm-vfp/OP_MUL_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fmuld d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_DOUBLE: /* 0xae */
+/* File: arm-vfp/OP_DIV_DOUBLE.S */
+/* File: arm-vfp/fbinopWide.S */
+ /*
+ * Generic 64-bit double-precision floating point binary operation.
+ * Provide an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * for: add-double, sub-double, mul-double, div-double
+ */
+ /* doubleop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ mov r3, r0, lsr #8 @ r3<- CC
+ and r2, r0, #255 @ r2<- BB
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vCC
+ VREG_INDEX_TO_ADDR(r2, r2) @ r2<- &vBB
+ fldd d1, [r3] @ d1<- vCC
+ fldd d0, [r2] @ d0<- vBB
+
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ fdivd d2, d0, d1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vAA
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_DOUBLE: /* 0xaf */
+/* File: armv5te/OP_REM_DOUBLE.S */
+/* EABI doesn't define a double remainder function, but libm does */
+/* File: armv5te/binopWide.S */
+ /*
+ * Generic 64-bit binary operation. Provide an "instr" line that
+ * specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * for: add-long, sub-long, div-long, rem-long, and-long, or-long,
+ * xor-long, add-double, sub-double, mul-double, div-double,
+ * rem-double
+ *
+ * IMPORTANT: you may specify "chkzero" or "preinstr" but not both.
+ */
+ /* binop vAA, vBB, vCC */
+ FETCH(r0, 1) @ r0<- CCBB
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r0, #255 @ r2<- BB
+ mov r3, r0, lsr #8 @ r3<- CC
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ add r2, rFP, r2, lsl #2 @ r2<- &fp[BB]
+ add r3, rFP, r3, lsl #2 @ r3<- &fp[CC]
+ ldmia r2, {r0-r1} @ r0/r1<- vBB/vBB+1
+ ldmia r3, {r2-r3} @ r2/r3<- vCC/vCC+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl fmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 14-17 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT_2ADDR: /* 0xb0 */
+/* File: armv6t2/OP_ADD_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_INT_2ADDR: /* 0xb1 */
+/* File: armv6t2/OP_SUB_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ sub r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT_2ADDR: /* 0xb2 */
+/* File: armv6t2/OP_MUL_INT_2ADDR.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT_2ADDR: /* 0xb3 */
+/* File: armv6t2/OP_DIV_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT_2ADDR: /* 0xb4 */
+/* File: armv6t2/OP_REM_INT_2ADDR.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT_2ADDR: /* 0xb5 */
+/* File: armv6t2/OP_AND_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT_2ADDR: /* 0xb6 */
+/* File: armv6t2/OP_OR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT_2ADDR: /* 0xb7 */
+/* File: armv6t2/OP_XOR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_INT_2ADDR: /* 0xb8 */
+/* File: armv6t2/OP_SHL_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_INT_2ADDR: /* 0xb9 */
+/* File: armv6t2/OP_SHR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_INT_2ADDR: /* 0xba */
+/* File: armv6t2/OP_USHR_INT_2ADDR.S */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_LONG_2ADDR: /* 0xbb */
+/* File: armv6t2/OP_ADD_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ adds r0, r0, r2 @ optional op; may set condition codes
+ adc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_LONG_2ADDR: /* 0xbc */
+/* File: armv6t2/OP_SUB_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ subs r0, r0, r2 @ optional op; may set condition codes
+ sbc r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_LONG_2ADDR: /* 0xbd */
+/* File: armv6t2/OP_MUL_LONG_2ADDR.S */
+ /*
+ * Signed 64-bit integer multiply, "/2addr" version.
+ *
+ * See OP_MUL_LONG for an explanation.
+ *
+ * We get a little tight on registers, so to avoid looking up &fp[A]
+ * again we stuff it into rINST.
+ */
+ /* mul-long/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add rINST, rFP, r9, lsl #2 @ rINST<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia rINST, {r0-r1} @ r0/r1<- vAA/vAA+1
+ mul ip, r2, r1 @ ip<- ZxW
+ umull r9, r10, r2, r0 @ r9/r10 <- ZxX
+ mla r2, r0, r3, ip @ r2<- YxX + (ZxW)
+ mov r0, rINST @ r0<- &fp[A] (free up rINST)
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ add r10, r2, r10 @ r10<- r10 + low(ZxW + (YxX))
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r0, {r9-r10} @ vAA/vAA+1<- r9/r10
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_LONG_2ADDR: /* 0xbe */
+/* File: armv6t2/OP_DIV_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_LONG_2ADDR: /* 0xbf */
+/* File: armv6t2/OP_REM_LONG_2ADDR.S */
+/* ldivmod returns quotient in r0/r1 and remainder in r2/r3 */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 1
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_ldivmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r2,r3} @ vAA/vAA+1<- r2/r3
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_LONG_2ADDR: /* 0xc0 */
+/* File: armv6t2/OP_AND_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ and r0, r0, r2 @ optional op; may set condition codes
+ and r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_LONG_2ADDR: /* 0xc1 */
+/* File: armv6t2/OP_OR_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ orr r0, r0, r2 @ optional op; may set condition codes
+ orr r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_LONG_2ADDR: /* 0xc2 */
+/* File: armv6t2/OP_XOR_LONG_2ADDR.S */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ eor r0, r0, r2 @ optional op; may set condition codes
+ eor r1, r1, r3 @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_LONG_2ADDR: /* 0xc3 */
+/* File: armv6t2/OP_SHL_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shl-long/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r1, r1, asl r2 @ r1<- r1 << r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r1, r1, r0, lsr r3 @ r1<- r1 | (r0 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r1, r0, asl ip @ if r2 >= 32, r1<- r0 << (r2-32)
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ b .LOP_SHL_LONG_2ADDR_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_LONG_2ADDR: /* 0xc4 */
+/* File: armv6t2/OP_SHR_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* shr-long/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r0, r1, asr ip @ if r2 >= 32, r0<-r1 >> (r2-32)
+ mov r1, r1, asr r2 @ r1<- r1 >> r2
+ b .LOP_SHR_LONG_2ADDR_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_LONG_2ADDR: /* 0xc5 */
+/* File: armv6t2/OP_USHR_LONG_2ADDR.S */
+ /*
+ * Long integer shift, 2addr version. vA is 64-bit value/result, vB is
+ * 32-bit shift distance.
+ */
+ /* ushr-long/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r2, r3) @ r2<- vB
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ and r2, r2, #63 @ r2<- r2 & 0x3f
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+
+ mov r0, r0, lsr r2 @ r0<- r2 >> r2
+ rsb r3, r2, #32 @ r3<- 32 - r2
+ orr r0, r0, r1, asl r3 @ r0<- r0 | (r1 << (32-r2))
+ subs ip, r2, #32 @ ip<- r2 - 32
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ movpl r0, r1, lsr ip @ if r2 >= 32, r0<-r1 >>> (r2-32)
+ mov r1, r1, lsr r2 @ r1<- r1 >>> r2
+ b .LOP_USHR_LONG_2ADDR_finish
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_FLOAT_2ADDR: /* 0xc6 */
+/* File: arm-vfp/OP_ADD_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fadds s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_FLOAT_2ADDR: /* 0xc7 */
+/* File: arm-vfp/OP_SUB_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fsubs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_FLOAT_2ADDR: /* 0xc8 */
+/* File: arm-vfp/OP_MUL_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fmuls s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_FLOAT_2ADDR: /* 0xc9 */
+/* File: arm-vfp/OP_DIV_FLOAT_2ADDR.S */
+/* File: arm-vfp/fbinop2addr.S */
+ /*
+ * Generic 32-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "s2 = s0 op s1".
+ *
+ * For: add-float/2addr, sub-float/2addr, mul-float/2addr, div-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ flds s1, [r3] @ s1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ flds s0, [r9] @ s0<- vA
+
+ fdivs s2, s0, s1 @ s2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fsts s2, [r9] @ vAA<- s2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_FLOAT_2ADDR: /* 0xca */
+/* File: armv6t2/OP_REM_FLOAT_2ADDR.S */
+/* EABI doesn't define a float remainder function, but libm does */
+/* File: armv6t2/binop2addr.S */
+ /*
+ * Generic 32-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/2addr, sub-int/2addr, mul-int/2addr, div-int/2addr,
+ * rem-int/2addr, and-int/2addr, or-int/2addr, xor-int/2addr,
+ * shl-int/2addr, shr-int/2addr, ushr-int/2addr, add-float/2addr,
+ * sub-float/2addr, mul-float/2addr, div-float/2addr, rem-float/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r1, r3) @ r1<- vB
+ GET_VREG(r0, r9) @ r0<- vA
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl fmodf @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_DOUBLE_2ADDR: /* 0xcb */
+/* File: arm-vfp/OP_ADD_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ faddd d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SUB_DOUBLE_2ADDR: /* 0xcc */
+/* File: arm-vfp/OP_SUB_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ fsubd d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_DOUBLE_2ADDR: /* 0xcd */
+/* File: arm-vfp/OP_MUL_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ fmuld d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_DOUBLE_2ADDR: /* 0xce */
+/* File: arm-vfp/OP_DIV_DOUBLE_2ADDR.S */
+/* File: arm-vfp/fbinopWide2addr.S */
+ /*
+ * Generic 64-bit floating point "/2addr" binary operation. Provide
+ * an "instr" line that specifies an instruction that performs
+ * "d2 = d0 op d1".
+ *
+ * For: add-double/2addr, sub-double/2addr, mul-double/2addr,
+ * div-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r3, rINST, lsr #12 @ r3<- B
+ mov r9, rINST, lsr #8 @ r9<- A+
+ VREG_INDEX_TO_ADDR(r3, r3) @ r3<- &vB
+ and r9, r9, #15 @ r9<- A
+ fldd d1, [r3] @ d1<- vB
+ VREG_INDEX_TO_ADDR(r9, r9) @ r9<- &vA
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+ fldd d0, [r9] @ d0<- vA
+
+ fdivd d2, d0, d1 @ d2<- op
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ fstd d2, [r9] @ vAA<- d2
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_DOUBLE_2ADDR: /* 0xcf */
+/* File: armv6t2/OP_REM_DOUBLE_2ADDR.S */
+/* EABI doesn't define a double remainder function, but libm does */
+/* File: armv6t2/binopWide2addr.S */
+ /*
+ * Generic 64-bit "/2addr" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0-r1 op r2-r3".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-long/2addr, sub-long/2addr, div-long/2addr, rem-long/2addr,
+ * and-long/2addr, or-long/2addr, xor-long/2addr, add-double/2addr,
+ * sub-double/2addr, mul-double/2addr, div-double/2addr,
+ * rem-double/2addr
+ */
+ /* binop/2addr vA, vB */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ add r1, rFP, r1, lsl #2 @ r1<- &fp[B]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[A]
+ ldmia r1, {r2-r3} @ r2/r3<- vBB/vBB+1
+ ldmia r9, {r0-r1} @ r0/r1<- vAA/vAA+1
+ .if 0
+ orrs ip, r2, r3 @ second arg (r2-r3) is zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(1) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl fmod @ result<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0,r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 12-15 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT_LIT16: /* 0xd0 */
+/* File: armv6t2/OP_ADD_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RSUB_INT: /* 0xd1 */
+/* File: armv6t2/OP_RSUB_INT.S */
+/* this op is "rsub-int", but can be thought of as "rsub-int/lit16" */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ rsb r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT_LIT16: /* 0xd2 */
+/* File: armv6t2/OP_MUL_INT_LIT16.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT_LIT16: /* 0xd3 */
+/* File: armv6t2/OP_DIV_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT_LIT16: /* 0xd4 */
+/* File: armv6t2/OP_REM_INT_LIT16.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 1
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT_LIT16: /* 0xd5 */
+/* File: armv6t2/OP_AND_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT_LIT16: /* 0xd6 */
+/* File: armv6t2/OP_OR_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT_LIT16: /* 0xd7 */
+/* File: armv6t2/OP_XOR_INT_LIT16.S */
+/* File: armv6t2/binopLit16.S */
+ /*
+ * Generic 32-bit "lit16" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit16, rsub-int, mul-int/lit16, div-int/lit16,
+ * rem-int/lit16, and-int/lit16, or-int/lit16, xor-int/lit16
+ */
+ /* binop/lit16 vA, vB, #+CCCC */
+ FETCH_S(r1, 1) @ r1<- ssssCCCC (sign-extended)
+ mov r2, rINST, lsr #12 @ r2<- B
+ ubfx r9, rINST, #8, #4 @ r9<- A
+ GET_VREG(r0, r2) @ r0<- vB
+ .if 0
+ cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-13 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_ADD_INT_LIT8: /* 0xd8 */
+/* File: armv5te/OP_ADD_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ add r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_RSUB_INT_LIT8: /* 0xd9 */
+/* File: armv5te/OP_RSUB_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ rsb r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_MUL_INT_LIT8: /* 0xda */
+/* File: armv5te/OP_MUL_INT_LIT8.S */
+/* must be "mul r0, r1, r0" -- "r0, r0, r1" is illegal */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ mul r0, r1, r0 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_DIV_INT_LIT8: /* 0xdb */
+/* File: armv5te/OP_DIV_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 1
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idiv @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_REM_INT_LIT8: /* 0xdc */
+/* File: armv5te/OP_REM_INT_LIT8.S */
+/* idivmod returns quotient in r0 and remainder in r1 */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 1
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ bl __aeabi_idivmod @ r1<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_AND_INT_LIT8: /* 0xdd */
+/* File: armv5te/OP_AND_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ and r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_OR_INT_LIT8: /* 0xde */
+/* File: armv5te/OP_OR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ orr r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_XOR_INT_LIT8: /* 0xdf */
+/* File: armv5te/OP_XOR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ @ optional op; may set condition codes
+ eor r0, r0, r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHL_INT_LIT8: /* 0xe0 */
+/* File: armv5te/OP_SHL_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asl r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_SHR_INT_LIT8: /* 0xe1 */
+/* File: armv5te/OP_SHR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, asr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_USHR_INT_LIT8: /* 0xe2 */
+/* File: armv5te/OP_USHR_INT_LIT8.S */
+/* File: armv5te/binopLit8.S */
+ /*
+ * Generic 32-bit "lit8" binary operation. Provide an "instr" line
+ * that specifies an instruction that performs "result = r0 op r1".
+ * This could be an ARM instruction or a function call. (If the result
+ * comes back in a register other than r0, you can override "result".)
+ *
+ * If "chkzero" is set to 1, we perform a divide-by-zero check on
+ * vCC (r1). Useful for integer division and modulus.
+ *
+ * For: add-int/lit8, rsub-int/lit8, mul-int/lit8, div-int/lit8,
+ * rem-int/lit8, and-int/lit8, or-int/lit8, xor-int/lit8,
+ * shl-int/lit8, shr-int/lit8, ushr-int/lit8
+ */
+ /* binop/lit8 vAA, vBB, #+CC */
+ FETCH_S(r3, 1) @ r3<- ssssCCBB (sign-extended for CC)
+ mov r9, rINST, lsr #8 @ r9<- AA
+ and r2, r3, #255 @ r2<- BB
+ GET_VREG(r0, r2) @ r0<- vBB
+ movs r1, r3, asr #8 @ r1<- ssssssCC (sign extended)
+ .if 0
+ @cmp r1, #0 @ is second operand zero?
+ beq common_errDivideByZero
+ .endif
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+
+ and r1, r1, #31 @ optional op; may set condition codes
+ mov r0, r0, lsr r1 @ r0<- op, r0-r3 changed
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+ /* 10-12 instructions */
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E3: /* 0xe3 */
+/* File: armv5te/OP_UNUSED_E3.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E4: /* 0xe4 */
+/* File: armv5te/OP_UNUSED_E4.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E5: /* 0xe5 */
+/* File: armv5te/OP_UNUSED_E5.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E6: /* 0xe6 */
+/* File: armv5te/OP_UNUSED_E6.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E7: /* 0xe7 */
+/* File: armv5te/OP_UNUSED_E7.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E8: /* 0xe8 */
+/* File: armv5te/OP_UNUSED_E8.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_E9: /* 0xe9 */
+/* File: armv5te/OP_UNUSED_E9.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EA: /* 0xea */
+/* File: armv5te/OP_UNUSED_EA.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EB: /* 0xeb */
+/* File: armv5te/OP_UNUSED_EB.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EC: /* 0xec */
+/* File: armv5te/OP_UNUSED_EC.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+/* File: armv5te/OP_THROW_VERIFICATION_ERROR.S */
+ /*
+ * Handle a throw-verification-error instruction. This throws an
+ * exception for an error discovered during verification. The
+ * exception is indicated by AA, with some detail provided by BBBB.
+ */
+ /* op AA, ref@BBBB */
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ FETCH(r2, 1) @ r2<- BBBB
+ EXPORT_PC() @ export the PC
+ mov r1, rINST, lsr #8 @ r1<- AA
+ bl dvmThrowVerificationError @ always throws
+ b common_exceptionThrown @ handle exception
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_EXECUTE_INLINE: /* 0xee */
+/* File: armv5te/OP_EXECUTE_INLINE.S */
+ /*
+ * Execute a "native inline" instruction.
+ *
+ * We need to call:
+ * dvmPerformInlineOp4Std(arg0, arg1, arg2, arg3, &retval, ref)
+ *
+ * The first four args are in r0-r3, but the last two must be pushed
+ * onto the stack.
+ */
+ /* [opt] execute-inline vAA, {vC, vD, vE, vF}, inline@BBBB */
+ FETCH(r10, 1) @ r10<- BBBB
+ add r1, rGLUE, #offGlue_retval @ r1<- &glue->retval
+ EXPORT_PC() @ can throw
+ sub sp, sp, #8 @ make room for arg(s)
+ mov r0, rINST, lsr #12 @ r0<- B
+ str r1, [sp] @ push &glue->retval
+ bl .LOP_EXECUTE_INLINE_continue @ make call; will return after
+ add sp, sp, #8 @ pop stack
+ cmp r0, #0 @ test boolean result of inline
+ beq common_exceptionThrown @ returned false, handle exception
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_EF: /* 0xef */
+/* File: armv5te/OP_UNUSED_EF.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_DIRECT_EMPTY: /* 0xf0 */
+/* File: armv5te/OP_INVOKE_DIRECT_EMPTY.S */
+ /*
+ * invoke-direct-empty is a no-op in a "standard" interpreter.
+ */
+ FETCH_ADVANCE_INST(3) @ advance to next instr, load rINST
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_F1: /* 0xf1 */
+/* File: armv5te/OP_UNUSED_F1.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IGET_QUICK: /* 0xf2 */
+/* File: armv6t2/OP_IGET_QUICK.S */
+ /* For: iget-quick, iget-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ FETCH(r1, 1) @ r1<- 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
+ ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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
+ 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)
+ 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 */
+/* File: armv5te/OP_IGET_OBJECT_QUICK.S */
+/* File: armv5te/OP_IGET_QUICK.S */
+ /* For: iget-quick, iget-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ GET_VREG(r3, r2) @ r3<- object we're operating on
+ 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
+ ldr r0, [r3, r1] @ r0<- obj.field (always 32 bits)
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ and r2, r2, #15
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r2) @ fp[A]<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_QUICK: /* 0xf5 */
+/* File: armv6t2/OP_IPUT_QUICK.S */
+ /* For: iput-quick, iput-object-quick */
+ /* op vA, vB, offset@CCCC */
+ mov r2, rINST, lsr #12 @ r2<- B
+ FETCH(r1, 1) @ r1<- field byte offset
+ GET_VREG(r3, r2) @ r3<- fp[B], the object pointer
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ cmp r3, #0 @ check object for null
+ beq common_errNullObject @ object was null
+ GET_VREG(r0, r2) @ r0<- fp[A]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_IPUT_WIDE_QUICK: /* 0xf6 */
+/* File: armv6t2/OP_IPUT_WIDE_QUICK.S */
+ /* iput-wide-quick vA, vB, offset@CCCC */
+ mov r1, rINST, lsr #12 @ r1<- B
+ ubfx r0, rINST, #8, #4 @ r0<- A
+ GET_VREG(r2, r1) @ r2<- fp[B], the object pointer
+ add r3, rFP, r0, lsl #2 @ r3<- &fp[A]
+ cmp r2, #0 @ check object for null
+ ldmia r3, {r0-r1} @ r0/r1<- fp[A]
+ beq common_errNullObject @ object was null
+ FETCH(r3, 1) @ r3<- field byte offset
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
+
+
+/* ------------------------------ */
+ .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 */
+ /* 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]
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK: /* 0xf8 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r3, 2) @ r3<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!0)
+ and r3, r3, #15 @ r3<- C (or stays CCCC)
+ .endif
+ GET_VREG(r2, r3) @ r2<- vC ("this" ptr)
+ cmp r2, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r2, [r2, #offObject_clazz] @ r2<- thisPtr->clazz
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- thisPtr->clazz->vtable
+ EXPORT_PC() @ invoke must export
+ ldr r0, [r2, r1, lsl #2] @ r3<- vtable[BBBB]
+ bl common_invokeMethodNoRange @ continue on
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_VIRTUAL_QUICK_RANGE: /* 0xf9 */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK_RANGE.S */
+/* File: armv5te/OP_INVOKE_VIRTUAL_QUICK.S */
+ /*
+ * Handle an optimized virtual method call.
+ *
+ * for: [opt] invoke-virtual-quick, invoke-virtual-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r3, 2) @ r3<- FEDC or CCCC
+ FETCH(r1, 1) @ r1<- BBBB
+ .if (!1)
+ and r3, r3, #15 @ r3<- C (or stays CCCC)
+ .endif
+ GET_VREG(r2, r3) @ r2<- vC ("this" ptr)
+ cmp r2, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r2, [r2, #offObject_clazz] @ r2<- thisPtr->clazz
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- thisPtr->clazz->vtable
+ EXPORT_PC() @ invoke must export
+ ldr r0, [r2, r1, lsl #2] @ r3<- vtable[BBBB]
+ bl common_invokeMethodRange @ continue on
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER_QUICK: /* 0xfa */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ .if (!0)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [r2, #offMethod_clazz] @ r2<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ ldr r2, [r2, #offClassObject_super] @ r2<- method->clazz->super
+ GET_VREG(r3, r10) @ r3<- "this"
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- ...clazz->super->vtable
+ cmp r3, #0 @ null "this" ref?
+ ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
+ beq common_errNullObject @ "this" is null, throw exception
+ bl common_invokeMethodNoRange @ continue on
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_INVOKE_SUPER_QUICK_RANGE: /* 0xfb */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK_RANGE.S */
+/* File: armv5te/OP_INVOKE_SUPER_QUICK.S */
+ /*
+ * Handle an optimized "super" method call.
+ *
+ * for: [opt] invoke-super-quick, invoke-super-quick/range
+ */
+ /* op vB, {vD, vE, vF, vG, vA}, class@CCCC */
+ /* op vAA, {vCCCC..v(CCCC+AA-1)}, meth@BBBB */
+ FETCH(r10, 2) @ r10<- GFED or CCCC
+ ldr r2, [rGLUE, #offGlue_method] @ r2<- current method
+ .if (!1)
+ and r10, r10, #15 @ r10<- D (or stays CCCC)
+ .endif
+ FETCH(r1, 1) @ r1<- BBBB
+ ldr r2, [r2, #offMethod_clazz] @ r2<- method->clazz
+ EXPORT_PC() @ must export for invoke
+ ldr r2, [r2, #offClassObject_super] @ r2<- method->clazz->super
+ GET_VREG(r3, r10) @ r3<- "this"
+ ldr r2, [r2, #offClassObject_vtable] @ r2<- ...clazz->super->vtable
+ cmp r3, #0 @ null "this" ref?
+ ldr r0, [r2, r1, lsl #2] @ r0<- super->vtable[BBBB]
+ beq common_errNullObject @ "this" is null, throw exception
+ 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
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_FD: /* 0xfd */
+/* File: armv5te/OP_UNUSED_FD.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_FE: /* 0xfe */
+/* File: armv5te/OP_UNUSED_FE.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+/* ------------------------------ */
+ .balign 64
+.L_OP_UNUSED_FF: /* 0xff */
+/* File: armv5te/OP_UNUSED_FF.S */
+/* File: armv5te/unused.S */
+ bl common_abort
+
+
+
+
+ .balign 64
+ .size dvmAsmInstructionStart, .-dvmAsmInstructionStart
+ .global dvmAsmInstructionEnd
+dvmAsmInstructionEnd:
+
+/*
+ * ===========================================================================
+ * Sister implementations
+ * ===========================================================================
+ */
+ .global dvmAsmSisterStart
+ .type dvmAsmSisterStart, %function
+ .text
+ .balign 4
+dvmAsmSisterStart:
+
+/* continuation for OP_CONST_STRING */
+
+ /*
+ * Continuation if the String has not yet been resolved.
+ * r1: BBBB (String ref)
+ * r9: target register
+ */
+.LOP_CONST_STRING_resolve:
+ EXPORT_PC()
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveString @ r0<- String reference
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yup, handle the exception
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_CONST_STRING_JUMBO */
+
+ /*
+ * Continuation if the String has not yet been resolved.
+ * r1: BBBBBBBB (String ref)
+ * r9: target register
+ */
+.LOP_CONST_STRING_JUMBO_resolve:
+ EXPORT_PC()
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveString @ r0<- String reference
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yup, handle the exception
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_CONST_CLASS */
+
+ /*
+ * Continuation if the Class has not yet been resolved.
+ * r1: BBBB (Class ref)
+ * r9: target register
+ */
+.LOP_CONST_CLASS_resolve:
+ EXPORT_PC()
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ mov r2, #1 @ r2<- true
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- Class reference
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yup, handle the exception
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r9) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_CHECK_CAST */
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * r0 holds obj->clazz
+ * r1 holds class resolved from BBBB
+ * r9 holds object
+ */
+.LOP_CHECK_CAST_fullcheck:
+ bl dvmInstanceofNonTrivial @ r0<- boolean result
+ cmp r0, #0 @ failed?
+ bne .LOP_CHECK_CAST_okay @ no, success
+
+ @ A cast has failed. We need to throw a ClassCastException with the
+ @ class of the object that failed to be cast.
+ EXPORT_PC() @ about to throw
+ ldr r3, [r9, #offObject_clazz] @ r3<- obj->clazz
+ ldr r0, .LstrClassCastExceptionPtr
+ ldr r1, [r3, #offClassObject_descriptor] @ r1<- obj->clazz->descriptor
+ bl dvmThrowExceptionWithClassMessage
+ b common_exceptionThrown
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * r2 holds BBBB
+ * r9 holds object
+ */
+.LOP_CHECK_CAST_resolve:
+ EXPORT_PC() @ resolve() could throw
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r1, r2 @ r1<- BBBB
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- resolved ClassObject ptr
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ mov r1, r0 @ r1<- class resolved from BBB
+ ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
+ b .LOP_CHECK_CAST_resolved @ pick up where we left off
+
+.LstrClassCastExceptionPtr:
+ .word .LstrClassCastException
+
+
+/* continuation for OP_INSTANCE_OF */
+
+ /*
+ * Trivial test failed, need to perform full check. This is common.
+ * r0 holds obj->clazz
+ * r1 holds class resolved from BBBB
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_fullcheck:
+ bl dvmInstanceofNonTrivial @ r0<- boolean result
+ @ fall through to OP_INSTANCE_OF_store
+
+ /*
+ * r0 holds boolean result
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_store:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+ /*
+ * Trivial test succeeded, save and bail.
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_trivial:
+ mov r0, #1 @ indicate success
+ @ could b OP_INSTANCE_OF_store, but copying is faster and cheaper
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r0, r9) @ vA<- r0
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * r3 holds BBBB
+ * r9 holds A
+ */
+.LOP_INSTANCE_OF_resolve:
+ EXPORT_PC() @ resolve() could throw
+ ldr r0, [rGLUE, #offGlue_method] @ r0<- glue->method
+ mov r1, r3 @ r1<- BBBB
+ mov r2, #1 @ r2<- true
+ ldr r0, [r0, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- resolved ClassObject ptr
+ cmp r0, #0 @ got null?
+ beq common_exceptionThrown @ yes, handle exception
+ mov r1, r0 @ r1<- class resolved from BBB
+ mov r3, rINST, lsr #12 @ r3<- B
+ GET_VREG(r0, r3) @ r0<- vB (object)
+ 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
+.LOP_NEW_INSTANCE_finish: @ r0=new object
+ mov r3, rINST, lsr #8 @ r3<- AA
+ cmp r0, #0 @ failed?
+ beq common_exceptionThrown @ yes, handle the exception
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ SET_VREG(r0, r3) @ vAA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+ /*
+ * Class initialization required.
+ *
+ * r0 holds class object
+ */
+.LOP_NEW_INSTANCE_needinit:
+ mov r9, r0 @ save r0
+ bl dvmInitClass @ initialize class
+ cmp r0, #0 @ check boolean result
+ mov r0, r9 @ restore r0
+ bne .LOP_NEW_INSTANCE_initialized @ success, continue
+ b common_exceptionThrown @ failed, deal with init exception
+
+ /*
+ * Resolution required. This is the least-likely path.
+ *
+ * r1 holds BBBB
+ */
+.LOP_NEW_INSTANCE_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- resolved ClassObject ptr
+ cmp r0, #0 @ got null?
+ bne .LOP_NEW_INSTANCE_resolved @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+.LstrInstantiationErrorPtr:
+ .word .LstrInstantiationError
+
+
+/* continuation for OP_NEW_ARRAY */
+
+
+ /*
+ * Resolve class. (This is an uncommon case.)
+ *
+ * r1 holds array length
+ * r2 holds class ref CCCC
+ */
+.LOP_NEW_ARRAY_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ mov r9, r1 @ r9<- length (save)
+ mov r1, r2 @ r1<- CCCC
+ mov r2, #0 @ r2<- false
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ bl dvmResolveClass @ r0<- call(clazz, ref)
+ cmp r0, #0 @ got null?
+ mov r1, r9 @ r1<- length (restore)
+ beq common_exceptionThrown @ yes, handle exception
+ @ fall through to OP_NEW_ARRAY_finish
+
+ /*
+ * Finish allocation.
+ *
+ * r0 holds class
+ * r1 holds array length
+ */
+.LOP_NEW_ARRAY_finish:
+ mov r2, #ALLOC_DONT_TRACK @ don't track in local refs table
+ bl dvmAllocArrayByClass @ r0<- call(clazz, length, flags)
+ cmp r0, #0 @ failed?
+ mov r2, rINST, lsr #8 @ r2<- A+
+ beq common_exceptionThrown @ yes, handle the exception
+ 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) @ vA<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_FILLED_NEW_ARRAY */
+
+ /*
+ * On entry:
+ * r0 holds array class
+ * r10 holds AA or BA
+ */
+.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]
+ .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?
+ mov r9, r1 @ save length in r9
+ bne .LOP_FILLED_NEW_ARRAY_notimpl @ no, not handled yet
+ bl dvmAllocArrayByClass @ r0<- call(arClass, length, flags)
+ cmp r0, #0 @ null return?
+ beq common_exceptionThrown @ alloc failed, handle exception
+
+ FETCH(r1, 2) @ r1<- FEDC or CCCC
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ 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
+ bmi 2f @ was zero, bail
+
+ @ copy values from registers into the array
+ @ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
+ .if 0
+ add r2, rFP, r1, lsl #2 @ r2<- &fp[CCCC]
+1: ldr r3, [r2], #4 @ r3<- *r2++
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .else
+ cmp r9, #4 @ length was initially 5?
+ and r2, r10, #15 @ r2<- A
+ bne 1f @ <= 4 args, branch
+ GET_VREG(r3, r2) @ r3<- vA
+ sub r9, r9, #1 @ count--
+ str r3, [r0, #16] @ contents[4] = vA
+1: and r2, r1, #15 @ r2<- F/E/D/C
+ GET_VREG(r3, r2) @ r3<- vF/vE/vD/vC
+ mov r1, r1, lsr #4 @ r1<- next reg in low 4
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .endif
+
+2:
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.LOP_FILLED_NEW_ARRAY_notimpl:
+ ldr r0, .L_strInternalError
+ ldr r1, .L_strFilledNewArrayNotImpl
+ bl dvmThrowException
+ b common_exceptionThrown
+
+ .if (!0) @ define in one or the other, not both
+.L_strFilledNewArrayNotImpl:
+ .word .LstrFilledNewArrayNotImpl
+.L_strInternalError:
+ .word .LstrInternalError
+ .endif
+
+
+/* continuation for OP_FILLED_NEW_ARRAY_RANGE */
+
+ /*
+ * On entry:
+ * r0 holds array class
+ * r10 holds AA or BA
+ */
+.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]
+ .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?
+ 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)
+ cmp r0, #0 @ null return?
+ beq common_exceptionThrown @ alloc failed, handle exception
+
+ FETCH(r1, 2) @ r1<- FEDC or CCCC
+ str r0, [rGLUE, #offGlue_retval] @ retval.l <- new array
+ 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
+ bmi 2f @ was zero, bail
+
+ @ copy values from registers into the array
+ @ r0=array, r1=CCCC/FEDC, r9=length (from AA or B), r10=AA/BA
+ .if 1
+ add r2, rFP, r1, lsl #2 @ r2<- &fp[CCCC]
+1: ldr r3, [r2], #4 @ r3<- *r2++
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .else
+ cmp r9, #4 @ length was initially 5?
+ and r2, r10, #15 @ r2<- A
+ bne 1f @ <= 4 args, branch
+ GET_VREG(r3, r2) @ r3<- vA
+ sub r9, r9, #1 @ count--
+ str r3, [r0, #16] @ contents[4] = vA
+1: and r2, r1, #15 @ r2<- F/E/D/C
+ GET_VREG(r3, r2) @ r3<- vF/vE/vD/vC
+ mov r1, r1, lsr #4 @ r1<- next reg in low 4
+ subs r9, r9, #1 @ count--
+ str r3, [r0], #4 @ *contents++ = vX
+ bpl 1b
+ @ continue at 2
+ .endif
+
+2:
+ GET_INST_OPCODE(ip) @ ip<- opcode from rINST
+ GOTO_OPCODE(ip) @ execute it
+
+ /*
+ * Throw an exception indicating that we have not implemented this
+ * mode of filled-new-array.
+ */
+.LOP_FILLED_NEW_ARRAY_RANGE_notimpl:
+ ldr r0, .L_strInternalError
+ ldr r1, .L_strFilledNewArrayNotImpl
+ bl dvmThrowException
+ b common_exceptionThrown
+
+ .if (!1) @ define in one or the other, not both
+.L_strFilledNewArrayNotImpl:
+ .word .LstrFilledNewArrayNotImpl
+.L_strInternalError:
+ .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:
+ mvn r1, #0 @ r1<- -1
+ @ Want to cond code the next mov so we can avoid branch, but don't see it;
+ @ instead, we just replicate the tail end.
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+.LOP_CMP_LONG_greater:
+ mov r1, #1 @ r1<- 1
+ @ fall through to _finish
+
+.LOP_CMP_LONG_finish:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ SET_VREG(r1, r9) @ vAA<- r1
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_AGET_WIDE */
+
+.LOP_AGET_WIDE_finish:
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ ldrd r2, [r0, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
+ add r9, rFP, r9, lsl #2 @ r9<- &fp[AA]
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ 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, #offArrayObject_contents] @ r2/r3<- vBB[vCC]
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_APUT_OBJECT */
+ /*
+ * On entry:
+ * r1 = vBB (arrayObj)
+ * r9 = vAA (obj)
+ * r10 = offset into array (vBB + vCC * width)
+ */
+.LOP_APUT_OBJECT_finish:
+ cmp r9, #0 @ storing null reference?
+ beq .LOP_APUT_OBJECT_skip_check @ yes, skip type checks
+ ldr r0, [r9, #offObject_clazz] @ r0<- obj->clazz
+ ldr r1, [r1, #offObject_clazz] @ r1<- arrayObj->clazz
+ bl dvmCanPutArrayElement @ test object type vs. array type
+ cmp r0, #0 @ okay?
+ beq common_errArrayStore @ no
+.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 */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_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)
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ FETCH_ADVANCE_INST(2) @ advance rPC, load rINST
+ 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 */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_WIDE_finish:
+ cmp r9, #0 @ check object for null
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ beq common_errNullObject @ object was null
+ ldrd r0, [r9, r3] @ r0/r1<- obj.field (64-bit align ok)
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ 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
+
+
+/* continuation for OP_IGET_OBJECT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_OBJECT_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)
+ 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_BOOLEAN */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_BOOLEAN_finish:
+ @bl common_squeak1
+ 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)
+ 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_BYTE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_BYTE_finish:
+ @bl common_squeak2
+ 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)
+ 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_CHAR */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_CHAR_finish:
+ @bl common_squeak3
+ 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)
+ 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_SHORT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IGET_SHORT_finish:
+ @bl common_squeak4
+ 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)
+ 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 */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_finish:
+ @bl common_squeak0
+ ldr r3, [r0, #offInstField_byteOffset] @ r3<- byte offset of field
+ ubfx r1, rINST, #8, #4 @ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_WIDE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_WIDE_finish:
+ ubfx r2, rINST, #8, #4 @ r2<- A
+ cmp r9, #0 @ check object for null
+ 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(ip) @ extract opcode from rINST
+ strd r0, [r9, r3] @ obj.field (64 bits, aligned)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_OBJECT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_OBJECT_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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_BOOLEAN */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_BOOLEAN_finish:
+ @bl common_squeak1
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_BYTE */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_BYTE_finish:
+ @bl common_squeak2
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_CHAR */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_CHAR_finish:
+ @bl common_squeak3
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_IPUT_SHORT */
+
+ /*
+ * Currently:
+ * r0 holds resolved field
+ * r9 holds object
+ */
+.LOP_IPUT_SHORT_finish:
+ @bl common_squeak4
+ 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
+ str r0, [r9, r3] @ obj.field (8/16/32 bits)<- r0
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_SGET */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_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_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
+ */
+.LOP_SGET_WIDE_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_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_OBJECT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_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_SGET_OBJECT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_BOOLEAN */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_BOOLEAN_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_BOOLEAN_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_BYTE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_BYTE_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_BYTE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_CHAR */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_CHAR_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_CHAR_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SGET_SHORT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SGET_SHORT_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_SHORT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_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_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]
+ */
+.LOP_SPUT_WIDE_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_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
+
+
+/* continuation for OP_SPUT_BOOLEAN */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_BOOLEAN_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_BOOLEAN_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT_BYTE */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_BYTE_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_BYTE_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT_CHAR */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_CHAR_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_CHAR_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_SPUT_SHORT */
+
+ /*
+ * Continuation if the field has not yet been resolved.
+ * r1: BBBB field ref
+ */
+.LOP_SPUT_SHORT_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_SHORT_finish @ yes, finish
+ b common_exceptionThrown @ no, handle exception
+
+
+/* continuation for OP_INVOKE_VIRTUAL */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r10 = C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.LOP_INVOKE_VIRTUAL_continue:
+ GET_VREG(r1, r10) @ r1<- "this" ptr
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ cmp r1, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r3, [r1, #offObject_clazz] @ r1<- thisPtr->clazz
+ ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
+ ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodNoRange @ continue on
+
+
+/* continuation for OP_INVOKE_SUPER */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r9 = method->clazz
+ */
+.LOP_INVOKE_SUPER_continue:
+ ldr r1, [r9, #offClassObject_super] @ r1<- method->clazz->super
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ ldr r3, [r1, #offClassObject_vtableCount] @ r3<- super->vtableCount
+ EXPORT_PC() @ must export for invoke
+ cmp r2, r3 @ compare (methodIndex, vtableCount)
+ bcs .LOP_INVOKE_SUPER_nsm @ method not present in superclass
+ ldr r1, [r1, #offClassObject_vtable] @ r1<- ...clazz->super->vtable
+ ldr r0, [r1, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodNoRange @ continue on
+
+.LOP_INVOKE_SUPER_resolve:
+ mov r0, r9 @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_SUPER_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * r0 = resolved base method
+ */
+.LOP_INVOKE_SUPER_nsm:
+ ldr r1, [r0, #offMethod_name] @ r1<- method name
+ b common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_DIRECT */
+
+ /*
+ * On entry:
+ * r1 = reference (BBBB or CCCC)
+ * r10 = "this" register
+ */
+.LOP_INVOKE_DIRECT_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_DIRECT @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
+ bne .LOP_INVOKE_DIRECT_finish @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+
+/* continuation for OP_INVOKE_VIRTUAL_RANGE */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r10 = C or CCCC (index of first arg, which is the "this" ptr)
+ */
+.LOP_INVOKE_VIRTUAL_RANGE_continue:
+ GET_VREG(r1, r10) @ r1<- "this" ptr
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ cmp r1, #0 @ is "this" null?
+ beq common_errNullObject @ null "this", throw exception
+ ldr r3, [r1, #offObject_clazz] @ r1<- thisPtr->clazz
+ ldr r3, [r3, #offClassObject_vtable] @ r3<- thisPtr->clazz->vtable
+ ldr r0, [r3, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodRange @ continue on
+
+
+/* continuation for OP_INVOKE_SUPER_RANGE */
+
+ /*
+ * At this point:
+ * r0 = resolved base method
+ * r9 = method->clazz
+ */
+.LOP_INVOKE_SUPER_RANGE_continue:
+ ldr r1, [r9, #offClassObject_super] @ r1<- method->clazz->super
+ ldrh r2, [r0, #offMethod_methodIndex] @ r2<- baseMethod->methodIndex
+ ldr r3, [r1, #offClassObject_vtableCount] @ r3<- super->vtableCount
+ EXPORT_PC() @ must export for invoke
+ cmp r2, r3 @ compare (methodIndex, vtableCount)
+ bcs .LOP_INVOKE_SUPER_RANGE_nsm @ method not present in superclass
+ ldr r1, [r1, #offClassObject_vtable] @ r1<- ...clazz->super->vtable
+ ldr r0, [r1, r2, lsl #2] @ r3<- vtable[methodIndex]
+ bl common_invokeMethodRange @ continue on
+
+.LOP_INVOKE_SUPER_RANGE_resolve:
+ mov r0, r9 @ r0<- method->clazz
+ mov r2, #METHOD_VIRTUAL @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ bne .LOP_INVOKE_SUPER_RANGE_continue @ no, continue
+ b common_exceptionThrown @ yes, handle exception
+
+ /*
+ * Throw a NoSuchMethodError with the method name as the message.
+ * r0 = resolved base method
+ */
+.LOP_INVOKE_SUPER_RANGE_nsm:
+ ldr r1, [r0, #offMethod_name] @ r1<- method name
+ b common_errNoSuchMethod
+
+
+/* continuation for OP_INVOKE_DIRECT_RANGE */
+
+ /*
+ * On entry:
+ * r1 = reference (BBBB or CCCC)
+ * r10 = "this" register
+ */
+.LOP_INVOKE_DIRECT_RANGE_resolve:
+ ldr r3, [rGLUE, #offGlue_method] @ r3<- glue->method
+ ldr r0, [r3, #offMethod_clazz] @ r0<- method->clazz
+ mov r2, #METHOD_DIRECT @ resolver method type
+ bl dvmResolveMethod @ r0<- call(clazz, ref, flags)
+ cmp r0, #0 @ got null?
+ GET_VREG(r2, r10) @ r2<- "this" ptr (reload)
+ 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.
+ *
+ * We have to clip values to long min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+f2l_doconv:
+ stmfd sp!, {r4, lr}
+ mov r1, #0x5f000000 @ (float)maxlong
+ mov r4, r0
+ bl __aeabi_fcmpge @ is arg >= maxlong?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0 @ return maxlong (7fffffff)
+ mvnne r1, #0x80000000
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, #0xdf000000 @ (float)minlong
+ bl __aeabi_fcmple @ is arg <= minlong?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0 @ return minlong (80000000)
+ movne r1, #0x80000000
+ ldmnefd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ mov r1, r4
+ bl __aeabi_fcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ moveq r1, #0 @ return zero for NaN
+ ldmeqfd sp!, {r4, pc}
+
+ mov r0, r4 @ recover arg
+ 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.
+ *
+ * We have to clip values to long min/max per the specification. The
+ * expected common case is a "reasonable" value that converts directly
+ * to modest integer. The EABI convert function isn't doing this for us.
+ */
+d2l_doconv:
+ stmfd sp!, {r4, r5, lr} @ save regs
+ mov r3, #0x43000000 @ maxlong, as a double (high word)
+ add r3, #0x00e00000 @ 0x43e00000
+ mov r2, #0 @ maxlong, as a double (low word)
+ sub sp, sp, #4 @ align for EABI
+ mov r4, r0 @ save a copy of r0
+ mov r5, r1 @ and r1
+ bl __aeabi_dcmpge @ is arg >= maxlong?
+ cmp r0, #0 @ nonzero == yes
+ mvnne r0, #0 @ return maxlong (7fffffffffffffff)
+ mvnne r1, #0x80000000
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r3, #0xc3000000 @ minlong, as a double (high word)
+ add r3, #0x00e00000 @ 0xc3e00000
+ mov r2, #0 @ minlong, as a double (low word)
+ bl __aeabi_dcmple @ is arg <= minlong?
+ cmp r0, #0 @ nonzero == yes
+ movne r0, #0 @ return minlong (8000000000000000)
+ movne r1, #0x80000000
+ bne 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ mov r2, r4 @ compare against self
+ mov r3, r5
+ bl __aeabi_dcmpeq @ is arg == self?
+ cmp r0, #0 @ zero == no
+ moveq r1, #0 @ return zero for NaN
+ beq 1f
+
+ mov r0, r4 @ recover arg
+ mov r1, r5
+ bl __aeabi_d2lz @ convert double to long
+
+1:
+ add sp, sp, #4
+ ldmfd sp!, {r4, r5, pc}
+
+
+/* continuation for OP_MUL_LONG */
+
+.LOP_MUL_LONG_finish:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ mov r0, r0, asl r2 @ r0<- r0 << r2
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ mov r1, r1, asr r2 @ r1<- r1 >> r2
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ mov r1, r1, lsr r2 @ r1<- r1 >>> r2
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ 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:
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ stmia r9, {r0-r1} @ vAA/vAA+1<- r0/r1
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+
+/* continuation for OP_EXECUTE_INLINE */
+
+ /*
+ * Extract args, call function.
+ * r0 = #of args (0-4)
+ * r10 = call index
+ * lr = return addr, above [DO NOT bl out of here w/o preserving LR]
+ *
+ * Other ideas:
+ * - Use a jump table from the main piece to jump directly into the
+ * AND/LDR pairs. Costs a data load, saves a branch.
+ * - Have five separate pieces that do the loading, so we can work the
+ * interleave a little better. Increases code size.
+ */
+.LOP_EXECUTE_INLINE_continue:
+ rsb r0, r0, #4 @ r0<- 4-r0
+ FETCH(r9, 2) @ r9<- FEDC
+ add pc, pc, r0, lsl #3 @ computed goto, 2 instrs each
+ bl common_abort @ (skipped due to ARM prefetch)
+4: and ip, r9, #0xf000 @ isolate F
+ ldr r3, [rFP, ip, lsr #10] @ r3<- vF (shift right 12, left 2)
+3: and ip, r9, #0x0f00 @ isolate E
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vE
+2: and ip, r9, #0x00f0 @ isolate D
+ ldr r1, [rFP, ip, lsr #2] @ r1<- vD
+1: and ip, r9, #0x000f @ isolate C
+ ldr r0, [rFP, ip, lsl #2] @ r0<- vC
+0:
+ ldr r9, .LOP_EXECUTE_INLINE_table @ table of InlineOperation
+ LDR_PC "[r9, r10, lsl #4]" @ sizeof=16, "func" is first entry
+ @ (not reached)
+
+.LOP_EXECUTE_INLINE_table:
+ .word gDvmInlineOpsTable
+
+
+ .size dvmAsmSisterStart, .-dvmAsmSisterStart
+ .global dvmAsmSisterEnd
+dvmAsmSisterEnd:
+
+/* File: armv5te/footer.S */
+
+/*
+ * ===========================================================================
+ * Common subroutines and data
+ * ===========================================================================
+ */
+
+
+
+ .text
+ .align 2
+
+#if defined(WITH_JIT)
+/*
+ * Return from the translation cache to the interpreter when the compiler is
+ * having issues translating/executing a Dalvik instruction. We have to skip
+ * the code cache lookup otherwise it is possible to indefinitely bouce
+ * between the interpreter and the code cache if the instruction that fails
+ * to be compiled happens to be at a trace start.
+ */
+ .global dvmJitToInterpPunt
+dvmJitToInterpPunt:
+ mov rPC, r0
+#ifdef EXIT_STATS
+ mov r0,lr
+ bl dvmBumpPunt;
+#endif
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ FETCH_INST()
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return to the interpreter to handle a single instruction.
+ * On entry:
+ * r0 <= PC
+ * r1 <= PC of resume instruction
+ * lr <= resume point in translation
+ */
+ .global dvmJitToInterpSingleStep
+dvmJitToInterpSingleStep:
+ str lr,[rGLUE,#offGlue_jitResume]
+ str r1,[rGLUE,#offGlue_jitResumePC]
+ mov r1,#kInterpEntryInstr
+ @ enum is 4 byte in aapcs-EABI
+ str r1, [rGLUE, #offGlue_entryPoint]
+ mov rPC,r0
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ mov r2,#kJitSingleStep @ Ask for single step and then revert
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp to bail to debug interp
+ b common_gotoBail
+
+
+/*
+ * Return from the translation cache and immediately request
+ * a translation for the exit target. Commonly used following
+ * invokes.
+ */
+ .global dvmJitToTraceSelect
+dvmJitToTraceSelect:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq 2f
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/* No translation, so request one if profiling isn't disabled*/
+2:
+ adrl rIBASE, dvmAsmInstructionStart
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_INST()
+ cmp r0, #0
+ bne common_selectTrace
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+
+/*
+ * Return from the translation cache to the interpreter.
+ * The return was done with a BLX from thumb mode, and
+ * the following 32-bit word contains the target rPC value.
+ * Note that lr (r14) will have its low-order bit set to denote
+ * its thumb-mode origin.
+ *
+ * We'll need to stash our lr origin away, recover the new
+ * target and then check to see if there is a translation available
+ * for our new target. If so, we do a translation chain and
+ * go back to native execution. Otherwise, it's back to the
+ * interpreter (after treating this entry as a potential
+ * trace start).
+ */
+ .global dvmJitToInterpNormal
+dvmJitToInterpNormal:
+ ldr rPC,[r14, #-1] @ get our target PC
+ add rINST,r14,#-5 @ save start of chain branch
+#ifdef EXIT_STATS
+ bl dvmBumpNormal
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ beq toInterpreter @ go if not, otherwise do chain
+ mov r1,rINST
+ bl dvmJitChain @ r0<- dvmJitChain(codeAddr,chainAddr)
+ cmp r0,#0 @ successful chain?
+ bxne r0 @ continue native execution
+ b toInterpreter @ didn't chain - resume with interpreter
+
+/*
+ * 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 EXIT_STATS
+ bl dvmBumpNoChain
+#endif
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ Is there a translation?
+ cmp r0,#0
+ bxne r0 @ continue native execution if so
+
+/*
+ * No translation, restore interpreter regs and start interpreting.
+ * rGLUE & rFP were preserved in the translated code, and rPC has
+ * already been restored by the time we get here. We'll need to set
+ * up rIBASE & rINST, and load the address of the JitTable into r0.
+ */
+toInterpreter:
+ EXPORT_PC()
+ adrl rIBASE, dvmAsmInstructionStart
+ 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
+ * next instruction to execute, and rINST should be already loaded with
+ * the next opcode word, and r0 holds a pointer to the jit profile
+ * table (pJitProfTable).
+ */
+common_testUpdateProfile:
+ cmp r0,#0
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE_IFEQ(ip) @ if not profiling, fallthrough otherwise */
+
+common_updateProfile:
+ eor r3,rPC,rPC,lsr #12 @ cheap, but fast hash function
+ lsl r3,r3,#20 @ shift out excess 4095
+ ldrb r1,[r0,r3,lsr #20] @ get counter
+ GET_INST_OPCODE(ip)
+ subs r1,r1,#1 @ decrement counter
+ strb r1,[r0,r3,lsr #20] @ and store it
+ GOTO_OPCODE_IFNE(ip) @ if not threshold, fallthrough otherwise */
+
+/*
+ * Here, we switch to the debug interpreter to request
+ * trace selection. First, though, check to see if there
+ * is already a native translation in place (and, if so,
+ * jump to it now).
+ */
+ mov r1,#255
+ strb r1,[r0,r3,lsr #20] @ reset counter
+ EXPORT_PC()
+ mov r0,rPC
+ bl dvmJitGetCodeAddr @ r0<- dvmJitGetCodeAddr(rPC)
+ cmp r0,#0
+ beq common_selectTrace
+ bxne r0 @ jump to the translation
+common_selectTrace:
+ mov r2,#kJitTSelectRequest @ ask for trace selection
+ str r2,[rGLUE,#offGlue_jitState]
+ mov r1,#1 @ set changeInterp
+ b common_gotoBail
+
+#endif
+
+/*
+ * Common code when a backward branch is taken.
+ *
+ * On entry:
+ * r9 is PC adjustment *in bytes*
+ */
+common_backwardBranch:
+ mov r0, #kInterpEntryInstr
+ bl common_periodicChecks
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ cmp r0,#0
+ bne common_updateProfile
+ GET_INST_OPCODE(ip)
+ GOTO_OPCODE(ip)
+#else
+ FETCH_ADVANCE_INST_RB(r9) @ update rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+
+/*
+ * Need to see if the thread needs to be suspended or debugger/profiler
+ * activity has begun.
+ *
+ * TODO: if JDWP isn't running, zero out pDebuggerActive pointer so we don't
+ * have to do the second ldr.
+ *
+ * TODO: reduce this so we're just checking a single location.
+ *
+ * On entry:
+ * r0 is reentry type, e.g. kInterpEntryInstr
+ * r9 is trampoline PC adjustment *in bytes*
+ */
+common_periodicChecks:
+ ldr r3, [rGLUE, #offGlue_pSelfSuspendCount] @ r3<- &suspendCount
+
+#if defined(WITH_DEBUGGER)
+ ldr r1, [rGLUE, #offGlue_pDebuggerActive] @ r1<- &debuggerActive
+#endif
+#if defined(WITH_PROFILER)
+ ldr r2, [rGLUE, #offGlue_pActiveProfilers] @ r2<- &activeProfilers
+#endif
+
+ ldr r3, [r3] @ r3<- suspendCount (int)
+
+#if defined(WITH_DEBUGGER)
+ ldrb r1, [r1] @ r1<- debuggerActive (boolean)
+#endif
+#if defined (WITH_PROFILER)
+ ldr r2, [r2] @ r2<- activeProfilers (int)
+#endif
+
+ cmp r3, #0 @ suspend pending?
+ bne 2f @ yes, do full suspension check
+
+#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
+#endif
+
+ bx lr @ nothing to do, return
+
+2: @ check suspend
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- glue->self
+ EXPORT_PC() @ need for precise GC
+ b dvmCheckSuspendPending @ suspend if necessary, then return
+
+3: @ debugger/profiler enabled, bail out
+ add rPC, rPC, r9 @ update rPC
+ str r0, [rGLUE, #offGlue_entryPoint]
+ mov r1, #1 @ "want switch" = true
+ b common_gotoBail
+
+
+/*
+ * The equivalent of "goto bail", this calls through the "bail handler".
+ *
+ * State registers will be saved to the "glue" area before bailing.
+ *
+ * On entry:
+ * r1 is "bool changeInterp", indicating if we want to switch to the
+ * other interpreter or just bail all the way out
+ */
+common_gotoBail:
+ SAVE_PC_FP_TO_GLUE() @ export state to "glue"
+ mov r0, rGLUE @ r0<- glue ptr
+ b dvmMterpStdBail @ call(glue, changeInterp)
+
+ @add r1, r1, #1 @ using (boolean+1)
+ @add r0, rGLUE, #offGlue_jmpBuf @ r0<- &glue->jmpBuf
+ @bl _longjmp @ does not return
+ @bl common_abort
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodRange:
+.LinvokeNewRange:
+ @ prepare to copy args to "outs" area of current frame
+ movs r2, rINST, lsr #8 @ r2<- AA (arg count) -- test for zero
+ SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
+ beq .LinvokeArgsDone @ if no args, skip the rest
+ FETCH(r1, 2) @ r1<- CCCC
+
+ @ r0=methodToCall, r1=CCCC, r2=count, r10=outs
+ @ (very few methods have > 10 args; could unroll for common cases)
+ add r3, rFP, r1, lsl #2 @ r3<- &fp[CCCC]
+ sub r10, r10, r2, lsl #2 @ r10<- "outs" area, for call args
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+1: ldr r1, [r3], #4 @ val = *fp++
+ subs r2, r2, #1 @ count--
+ str r1, [r10], #4 @ *outs++ = val
+ bne 1b @ ...while count != 0
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ b .LinvokeArgsDone
+
+/*
+ * Common code for method invocation without range.
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ */
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ @ prepare to copy args to "outs" area of current frame
+ movs r2, rINST, lsr #12 @ r2<- B (arg count) -- test for zero
+ SAVEAREA_FROM_FP(r10, rFP) @ r10<- stack save area
+ FETCH(r1, 2) @ r1<- GFED (load here to hide latency)
+ ldrh r9, [r0, #offMethod_registersSize] @ r9<- methodToCall->regsSize
+ ldrh r3, [r0, #offMethod_outsSize] @ r3<- methodToCall->outsSize
+ beq .LinvokeArgsDone
+
+ @ r0=methodToCall, r1=GFED, r3=outSize, r2=count, r9=regSize, r10=outs
+.LinvokeNonRange:
+ rsb r2, r2, #5 @ r2<- 5-r2
+ add pc, pc, r2, lsl #4 @ computed goto, 4 instrs each
+ bl common_abort @ (skipped due to ARM prefetch)
+5: and ip, rINST, #0x0f00 @ isolate A
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vA (shift right 8, left 2)
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vA
+4: and ip, r1, #0xf000 @ isolate G
+ ldr r2, [rFP, ip, lsr #10] @ r2<- vG (shift right 12, left 2)
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vG
+3: and ip, r1, #0x0f00 @ isolate F
+ ldr r2, [rFP, ip, lsr #6] @ r2<- vF
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vF
+2: and ip, r1, #0x00f0 @ isolate E
+ ldr r2, [rFP, ip, lsr #2] @ r2<- vE
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vE
+1: and ip, r1, #0x000f @ isolate D
+ ldr r2, [rFP, ip, lsl #2] @ r2<- vD
+ mov r0, r0 @ nop
+ str r2, [r10, #-4]! @ *--outs = vD
+0: @ fall through to .LinvokeArgsDone
+
+.LinvokeArgsDone: @ r0=methodToCall, r3=outSize, r9=regSize
+ ldr r2, [r0, #offMethod_insns] @ r2<- method->insns
+ ldr rINST, [r0, #offMethod_clazz] @ rINST<- method->clazz
+ @ find space for the new stack frame, check for overflow
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- stack save area
+ sub r1, r1, r9, lsl #2 @ r1<- newFp (old savearea - regsSize)
+ SAVEAREA_FROM_FP(r10, r1) @ r10<- newSaveArea
+@ bl common_dumpRegs
+ ldr r9, [rGLUE, #offGlue_interpStackEnd] @ r9<- interpStackEnd
+ 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
+
+ @ set up newSaveArea
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(ip, rFP) @ ip<- stack save area
+ str ip, [r10, #offStackSaveArea_prevSave]
+#endif
+ str rFP, [r10, #offStackSaveArea_prevFrame]
+ str rPC, [r10, #offStackSaveArea_savedPc]
+#if defined(WITH_JIT)
+ mov r9, #0
+ str r9, [r10, #offStackSaveArea_returnAddr]
+#endif
+ str r0, [r10, #offStackSaveArea_method]
+ tst r3, #ACC_NATIVE
+ bne .LinvokeNative
+
+ /*
+ stmfd sp!, {r0-r3}
+ bl common_printNewline
+ mov r0, rFP
+ mov r1, #0
+ bl dvmDumpFp
+ ldmfd sp!, {r0-r3}
+ stmfd sp!, {r0-r3}
+ mov r0, r1
+ mov r1, r10
+ bl dvmDumpFp
+ bl common_printNewline
+ ldmfd sp!, {r0-r3}
+ */
+
+ ldrh r9, [r2] @ r9 <- load INST from new PC
+ ldr r3, [rINST, #offClassObject_pDvmDex] @ r3<- method->clazz->pDvmDex
+ mov rPC, r2 @ publish new rPC
+ ldr r2, [rGLUE, #offGlue_self] @ r2<- glue->self
+
+ @ Update "glue" values for the new method
+ @ r0=methodToCall, r1=newFp, r2=self, r3=newMethodClass, r9=newINST
+ str r0, [rGLUE, #offGlue_method] @ glue->method = methodToCall
+ str r3, [rGLUE, #offGlue_methodClassDex] @ glue->methodClassDex = ...
+#if defined(WITH_JIT)
+ GET_JIT_PROF_TABLE(r0)
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ cmp r0,#0
+ bne common_updateProfile
+ GOTO_OPCODE(ip) @ jump to next instruction
+#else
+ mov rFP, r1 @ fp = newFp
+ GET_PREFETCHED_OPCODE(ip, r9) @ extract prefetched opcode from r9
+ mov rINST, r9 @ publish new rINST
+ str r1, [r2, #offThread_curFrame] @ self->curFrame = newFp
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+.LinvokeNative:
+ @ Prep for the native call
+ @ r0=methodToCall, r1=newFp, r10=newSaveArea
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ ldr r9, [r3, #offThread_jniLocal_nextEntry] @ r9<- thread->refNext
+ str r1, [r3, #offThread_curFrame] @ self->curFrame = newFp
+ str r9, [r10, #offStackSaveArea_localRefTop] @newFp->localRefTop=refNext
+ mov r9, r3 @ r9<- glue->self (preserve)
+
+ mov r2, r0 @ r2<- methodToCall
+ mov r0, r1 @ r0<- newFp (points to args)
+ add r1, rGLUE, #offGlue_retval @ r1<- &retval
+
+#ifdef ASSIST_DEBUGGER
+ /* insert fake function header to help gdb find the stack frame */
+ b .Lskip
+ .type dalvik_mterp, %function
+dalvik_mterp:
+ .fnstart
+ MTERP_ENTRY1
+ MTERP_ENTRY2
+.Lskip:
+#endif
+
+ @mov lr, pc @ set return addr
+ @ldr pc, [r2, #offMethod_nativeFunc] @ pc<- methodToCall->nativeFunc
+ LDR_PC_LR "[r2, #offMethod_nativeFunc]"
+
+ @ native return; r9=self, r10=newSaveArea
+ @ equivalent to dvmPopJniLocals
+ ldr r0, [r10, #offStackSaveArea_localRefTop] @ r0<- newSave->localRefTop
+ ldr r1, [r9, #offThread_exception] @ check for exception
+ str rFP, [r9, #offThread_curFrame] @ self->curFrame = fp
+ cmp r1, #0 @ null?
+ str r0, [r9, #offThread_jniLocal_nextEntry] @ self->refNext<- r0
+ bne common_exceptionThrown @ no, handle exception
+
+ FETCH_ADVANCE_INST(3) @ advance rPC, load rINST
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+.LstackOverflow:
+ ldr r0, [rGLUE, #offGlue_self] @ r0<- self
+ bl dvmHandleStackOverflow
+ b common_exceptionThrown
+#ifdef ASSIST_DEBUGGER
+ .fnend
+#endif
+
+
+ /*
+ * Common code for method invocation, calling through "glue code".
+ *
+ * TODO: now that we have range and non-range invoke handlers, this
+ * needs to be split into two. Maybe just create entry points
+ * that set r9 and jump here?
+ *
+ * On entry:
+ * r0 is "Method* methodToCall", the method we're trying to call
+ * r9 is "bool methodCallRange", indicating if this is a /range variant
+ */
+ .if 0
+.LinvokeOld:
+ sub sp, sp, #8 @ space for args + pad
+ FETCH(ip, 2) @ ip<- FEDC or CCCC
+ mov r2, r0 @ A2<- methodToCall
+ mov r0, rGLUE @ A0<- glue
+ SAVE_PC_FP_TO_GLUE() @ export state to "glue"
+ mov r1, r9 @ A1<- methodCallRange
+ mov r3, rINST, lsr #8 @ A3<- AA
+ str ip, [sp, #0] @ A4<- ip
+ bl dvmMterp_invokeMethod @ call the C invokeMethod
+ add sp, sp, #8 @ remove arg area
+ b common_resumeAfterGlueCall @ continue to next instruction
+ .endif
+
+
+
+/*
+ * Common code for handling a return instruction.
+ *
+ * This does not return.
+ */
+common_returnFromMethod:
+.LreturnNew:
+ mov r0, #kInterpEntryReturn
+ mov r9, #0
+ bl common_periodicChecks
+
+ SAVEAREA_FROM_FP(r0, rFP) @ r0<- saveArea (old)
+ ldr rFP, [r0, #offStackSaveArea_prevFrame] @ fp = saveArea->prevFrame
+ ldr r9, [r0, #offStackSaveArea_savedPc] @ r9 = saveArea->savedPc
+ ldr r2, [rFP, #(offStackSaveArea_method - sizeofStackSaveArea)]
+ @ r2<- method we're returning to
+ ldr r3, [rGLUE, #offGlue_self] @ r3<- glue->self
+ cmp r2, #0 @ is this a break frame?
+ ldrne r10, [r2, #offMethod_clazz] @ r10<- method->clazz
+ mov r1, #0 @ "want switch" = false
+ beq common_gotoBail @ break frame, bail out completely
+
+ PREFETCH_ADVANCE_INST(rINST, r9, 3) @ advance r9, update new rINST
+ str r2, [rGLUE, #offGlue_method]@ glue->method = newSave->method
+ ldr r1, [r10, #offClassObject_pDvmDex] @ r1<- method->clazz->pDvmDex
+ str rFP, [r3, #offThread_curFrame] @ self->curFrame = fp
+#if defined(WITH_JIT)
+ ldr r3, [r0, #offStackSaveArea_returnAddr] @ r3 = saveArea->returnAddr
+ GET_JIT_PROF_TABLE(r0)
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ cmp r3, #0 @ caller is compiled code
+ blxne r3
+ 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
+ mov rPC, r9 @ publish new rPC
+ str r1, [rGLUE, #offGlue_methodClassDex]
+ GOTO_OPCODE(ip) @ jump to next instruction
+#endif
+
+ /*
+ * Return handling, calls through "glue code".
+ */
+ .if 0
+.LreturnOld:
+ SAVE_PC_FP_TO_GLUE() @ export state
+ mov r0, rGLUE @ arg to function
+ bl dvmMterp_returnFromMethod
+ b common_resumeAfterGlueCall
+ .endif
+
+
+/*
+ * Somebody has thrown an exception. Handle it.
+ *
+ * If the exception processing code returns to us (instead of falling
+ * out of the interpreter), continue with whatever the next instruction
+ * now happens to be.
+ *
+ * This does not return.
+ */
+ .global dvmMterpCommonExceptionThrown
+dvmMterpCommonExceptionThrown:
+common_exceptionThrown:
+.LexceptionNew:
+ mov r0, #kInterpEntryThrow
+ mov r9, #0
+ bl common_periodicChecks
+
+#if defined(WITH_JIT)
+ mov r2,#kJitTSelectAbort @ abandon trace selection in progress
+ str r2,[rGLUE,#offGlue_jitState]
+#endif
+
+ ldr r10, [rGLUE, #offGlue_self] @ r10<- glue->self
+ ldr r9, [r10, #offThread_exception] @ r9<- self->exception
+ mov r1, r10 @ r1<- self
+ mov r0, r9 @ r0<- exception
+ bl dvmAddTrackedAlloc @ don't let the exception be GCed
+ mov r3, #0 @ r3<- NULL
+ str r3, [r10, #offThread_exception] @ self->exception = NULL
+
+ /* set up args and a local for "&fp" */
+ /* (str sp, [sp, #-4]! would be perfect here, but is discouraged) */
+ str rFP, [sp, #-4]! @ *--sp = fp
+ mov ip, sp @ ip<- &fp
+ mov r3, #0 @ r3<- false
+ str ip, [sp, #-4]! @ *--sp = &fp
+ ldr r1, [rGLUE, #offGlue_method] @ r1<- glue->method
+ mov r0, r10 @ r0<- self
+ ldr r1, [r1, #offMethod_insns] @ r1<- method->insns
+ mov r2, r9 @ r2<- exception
+ sub r1, rPC, r1 @ r1<- pc - method->insns
+ mov r1, r1, asr #1 @ r1<- offset in code units
+
+ /* call, r0 gets catchRelPc (a code-unit offset) */
+ bl dvmFindCatchBlock @ call(self, relPc, exc, scan?, &fp)
+
+ /* fix earlier stack overflow if necessary; may trash rFP */
+ ldrb r1, [r10, #offThread_stackOverflowed]
+ cmp r1, #0 @ did we overflow earlier?
+ beq 1f @ no, skip ahead
+ mov rFP, r0 @ save relPc result in rFP
+ mov r0, r10 @ r0<- self
+ bl dvmCleanupStackOverflow @ call(self)
+ mov r0, rFP @ restore result
+1:
+
+ /* update frame pointer and check result from dvmFindCatchBlock */
+ ldr rFP, [sp, #4] @ retrieve the updated rFP
+ cmp r0, #0 @ is catchRelPc < 0?
+ add sp, sp, #8 @ restore stack
+ bmi .LnotCaughtLocally
+
+ /* adjust locals to match self->curFrame and updated PC */
+ SAVEAREA_FROM_FP(r1, rFP) @ r1<- new save area
+ ldr r1, [r1, #offStackSaveArea_method] @ r1<- new method
+ str r1, [rGLUE, #offGlue_method] @ glue->method = new method
+ ldr r2, [r1, #offMethod_clazz] @ r2<- method->clazz
+ ldr r3, [r1, #offMethod_insns] @ r3<- method->insns
+ ldr r2, [r2, #offClassObject_pDvmDex] @ r2<- method->clazz->pDvmDex
+ add rPC, r3, r0, asl #1 @ rPC<- method->insns + catchRelPc
+ str r2, [rGLUE, #offGlue_methodClassDex] @ glue->pDvmDex = meth...
+
+ /* release the tracked alloc on the exception */
+ mov r0, r9 @ r0<- exception
+ mov r1, r10 @ r1<- self
+ bl dvmReleaseTrackedAlloc @ release the exception
+
+ /* restore the exception if the handler wants it */
+ FETCH_INST() @ load rINST from rPC
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ cmp ip, #OP_MOVE_EXCEPTION @ is it "move-exception"?
+ streq r9, [r10, #offThread_exception] @ yes, restore the exception
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+.LnotCaughtLocally: @ r9=exception, r10=self
+ /* fix stack overflow if necessary */
+ ldrb r1, [r10, #offThread_stackOverflowed]
+ cmp r1, #0 @ did we overflow earlier?
+ movne r0, r10 @ if yes: r0<- self
+ blne dvmCleanupStackOverflow @ if yes: call(self)
+
+ @ may want to show "not caught locally" debug messages here
+#if DVM_SHOW_EXCEPTION >= 2
+ /* call __android_log_print(prio, tag, format, ...) */
+ /* "Exception %s from %s:%d not caught locally" */
+ @ dvmLineNumFromPC(method, pc - method->insns)
+ ldr r0, [rGLUE, #offGlue_method]
+ ldr r1, [r0, #offMethod_insns]
+ sub r1, rPC, r1
+ asr r1, r1, #1
+ bl dvmLineNumFromPC
+ str r0, [sp, #-4]!
+ @ dvmGetMethodSourceFile(method)
+ ldr r0, [rGLUE, #offGlue_method]
+ bl dvmGetMethodSourceFile
+ str r0, [sp, #-4]!
+ @ exception->clazz->descriptor
+ ldr r3, [r9, #offObject_clazz]
+ ldr r3, [r3, #offClassObject_descriptor]
+ @
+ ldr r2, strExceptionNotCaughtLocally
+ ldr r1, strLogTag
+ mov r0, #3 @ LOG_DEBUG
+ bl __android_log_print
+#endif
+ str r9, [r10, #offThread_exception] @ restore exception
+ mov r0, r9 @ r0<- exception
+ mov r1, r10 @ r1<- self
+ bl dvmReleaseTrackedAlloc @ release the exception
+ mov r1, #0 @ "want switch" = false
+ b common_gotoBail @ bail out
+
+
+ /*
+ * Exception handling, calls through "glue code".
+ */
+ .if 0
+.LexceptionOld:
+ SAVE_PC_FP_TO_GLUE() @ export state
+ mov r0, rGLUE @ arg to function
+ bl dvmMterp_exceptionThrown
+ b common_resumeAfterGlueCall
+ .endif
+
+
+/*
+ * After returning from a "glued" function, pull out the updated
+ * values and start executing at the next instruction.
+ */
+common_resumeAfterGlueCall:
+ LOAD_PC_FP_FROM_GLUE() @ pull rPC and rFP out of glue
+ FETCH_INST() @ load rINST from rPC
+ GET_INST_OPCODE(ip) @ extract opcode from rINST
+ GOTO_OPCODE(ip) @ jump to next instruction
+
+/*
+ * Invalid array index.
+ */
+common_errArrayIndex:
+ EXPORT_PC()
+ ldr r0, strArrayIndexException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Invalid array value.
+ */
+common_errArrayStore:
+ EXPORT_PC()
+ ldr r0, strArrayStoreException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Integer divide or mod by zero.
+ */
+common_errDivideByZero:
+ EXPORT_PC()
+ ldr r0, strArithmeticException
+ ldr r1, strDivideByZero
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Attempt to allocate an array with a negative size.
+ */
+common_errNegativeArraySize:
+ EXPORT_PC()
+ ldr r0, strNegativeArraySizeException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * Invocation of a non-existent method.
+ */
+common_errNoSuchMethod:
+ EXPORT_PC()
+ ldr r0, strNoSuchMethodError
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * We encountered a null object when we weren't expecting one. We
+ * export the PC, throw a NullPointerException, and goto the exception
+ * processing code.
+ */
+common_errNullObject:
+ EXPORT_PC()
+ ldr r0, strNullPointerException
+ mov r1, #0
+ bl dvmThrowException
+ b common_exceptionThrown
+
+/*
+ * For debugging, cause an immediate fault. The source address will
+ * be in lr (use a bl instruction to jump here).
+ */
+common_abort:
+ ldr pc, .LdeadFood
+.LdeadFood:
+ .word 0xdeadf00d
+
+/*
+ * Spit out a "we were here", preserving all registers. (The attempt
+ * to save ip won't work, but we need to save an even number of
+ * registers for EABI 64-bit stack alignment.)
+ */
+ .macro SQUEAK num
+common_squeak\num:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ ldr r0, strSqueak
+ mov r1, #\num
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+ .endm
+
+ SQUEAK 0
+ SQUEAK 1
+ SQUEAK 2
+ SQUEAK 3
+ SQUEAK 4
+ SQUEAK 5
+
+/*
+ * Spit out the number in r0, preserving registers.
+ */
+common_printNum:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ mov r1, r0
+ ldr r0, strSqueak
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Print a newline, preserving registers.
+ */
+common_printNewline:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ ldr r0, strNewline
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+ /*
+ * Print the 32-bit quantity in r0 as a hex value, preserving registers.
+ */
+common_printHex:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ mov r1, r0
+ ldr r0, strPrintHex
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Print the 64-bit quantity in r0-r1, preserving registers.
+ */
+common_printLong:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ mov r3, r1
+ mov r2, r0
+ ldr r0, strPrintLong
+ bl printf
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Print full method info. Pass the Method* in r0. Preserves regs.
+ */
+common_printMethod:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bl dvmMterpPrintMethod
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+
+/*
+ * Call a C helper function that dumps regs and possibly some
+ * additional info. Requires the C function to be compiled in.
+ */
+ .if 0
+common_dumpRegs:
+ stmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bl dvmMterpDumpArmRegs
+ ldmfd sp!, {r0, r1, r2, r3, ip, lr}
+ bx lr
+ .endif
+
+#if 0
+/*
+ * Experiment on VFP mode.
+ *
+ * uint32_t setFPSCR(uint32_t val, uint32_t mask)
+ *
+ * Updates the bits specified by "mask", setting them to the values in "val".
+ */
+setFPSCR:
+ and r0, r0, r1 @ make sure no stray bits are set
+ fmrx r2, fpscr @ get VFP reg
+ mvn r1, r1 @ bit-invert mask
+ and r2, r2, r1 @ clear masked bits
+ orr r2, r2, r0 @ set specified bits
+ fmxr fpscr, r2 @ set VFP reg
+ mov r0, r2 @ return new value
+ bx lr
+
+ .align 2
+ .global dvmConfigureFP
+ .type dvmConfigureFP, %function
+dvmConfigureFP:
+ stmfd sp!, {ip, lr}
+ /* 0x03000000 sets DN/FZ */
+ /* 0x00009f00 clears the six exception enable flags */
+ bl common_squeak0
+ mov r0, #0x03000000 @ r0<- 0x03000000
+ add r1, r0, #0x9f00 @ r1<- 0x03009f00
+ bl setFPSCR
+ ldmfd sp!, {ip, pc}
+#endif
+
+
+/*
+ * String references, must be close to the code that uses them.
+ */
+ .align 2
+strArithmeticException:
+ .word .LstrArithmeticException
+strArrayIndexException:
+ .word .LstrArrayIndexException
+strArrayStoreException:
+ .word .LstrArrayStoreException
+strDivideByZero:
+ .word .LstrDivideByZero
+strNegativeArraySizeException:
+ .word .LstrNegativeArraySizeException
+strNoSuchMethodError:
+ .word .LstrNoSuchMethodError
+strNullPointerException:
+ .word .LstrNullPointerException
+
+strLogTag:
+ .word .LstrLogTag
+strExceptionNotCaughtLocally:
+ .word .LstrExceptionNotCaughtLocally
+
+strNewline:
+ .word .LstrNewline
+strSqueak:
+ .word .LstrSqueak
+strPrintHex:
+ .word .LstrPrintHex
+strPrintLong:
+ .word .LstrPrintLong
+
+/*
+ * Zero-terminated ASCII string data.
+ *
+ * On ARM we have two choices: do like gcc does, and LDR from a .word
+ * with the address, or use an ADR pseudo-op to get the address
+ * directly. ADR saves 4 bytes and an indirection, but it's using a
+ * PC-relative addressing mode and hence has a limited range, which
+ * makes it not work well with mergeable string sections.
+ */
+ .section .rodata.str1.4,"aMS",%progbits,1
+
+.LstrBadEntryPoint:
+ .asciz "Bad entry point %d\n"
+.LstrArithmeticException:
+ .asciz "Ljava/lang/ArithmeticException;"
+.LstrArrayIndexException:
+ .asciz "Ljava/lang/ArrayIndexOutOfBoundsException;"
+.LstrArrayStoreException:
+ .asciz "Ljava/lang/ArrayStoreException;"
+.LstrClassCastException:
+ .asciz "Ljava/lang/ClassCastException;"
+.LstrDivideByZero:
+ .asciz "divide by zero"
+.LstrFilledNewArrayNotImpl:
+ .asciz "filled-new-array only implemented for objects and 'int'"
+.LstrInternalError:
+ .asciz "Ljava/lang/InternalError;"
+.LstrInstantiationError:
+ .asciz "Ljava/lang/InstantiationError;"
+.LstrNegativeArraySizeException:
+ .asciz "Ljava/lang/NegativeArraySizeException;"
+.LstrNoSuchMethodError:
+ .asciz "Ljava/lang/NoSuchMethodError;"
+.LstrNullPointerException:
+ .asciz "Ljava/lang/NullPointerException;"
+
+.LstrLogTag:
+ .asciz "mterp"
+.LstrExceptionNotCaughtLocally:
+ .asciz "Exception %s from %s:%d not caught locally\n"
+
+.LstrNewline:
+ .asciz "\n"
+.LstrSqueak:
+ .asciz "<%d>"
+.LstrPrintHex:
+ .asciz "<0x%x>"
+.LstrPrintLong:
+ .asciz "<%lld>"
+
+
diff --git a/vm/mterp/out/InterpAsm-x86.S b/vm/mterp/out/InterpAsm-x86.S
index a80e59e..2df6c20 100644
--- a/vm/mterp/out/InterpAsm-x86.S
+++ b/vm/mterp/out/InterpAsm-x86.S
@@ -682,9 +682,7 @@
movl offGlue_self(%ecx),%ecx # ecx<- glue->self
FETCH_INST_WORD(1)
testl %eax,%eax # null object?
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC()
-#endif
+ EXPORT_PC() # need for precise GC, MONITOR_TRACKING
jne .LOP_MONITOR_ENTER_continue
jmp common_errNullObject
@@ -2854,9 +2852,7 @@
.LOP_INVOKE_DIRECT_finish:
UNSPILL(rPC)
testl %ecx,%ecx # null "this"?
- movl $0,%ecx
- #jne common_invokeMethodNoRange # no, continue on
- jne common_invokeOld # no, continue on, eax<- method, ecx<- methodCallRange
+ jne common_invokeMethodNoRange # no, continue on
jmp common_errNullObject
/* ------------------------------ */
@@ -2876,10 +2872,8 @@
EXPORT_PC()
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
- movl $0,%ecx # needed by common_invokeOld - revisit
testl %eax,%eax
- #jne common_invokeMethodNoRange
- jne common_invokeOld
+ jne common_invokeMethodNoRange
GET_GLUE(%ecx)
movl offGlue_method(%ecx),%ecx # ecx<- glue->method
movzwl 2(rPC),%eax
@@ -3021,9 +3015,7 @@
.LOP_INVOKE_DIRECT_RANGE_finish:
UNSPILL(rPC)
testl %ecx,%ecx # null "this"?
- movl $1,%ecx
- #jne common_invokeMethodRange # no, continue on
- jne common_invokeOld # no, continue on, eax<- method, ecx<- methodCallRange
+ jne common_invokeMethodRange # no, continue on
jmp common_errNullObject
@@ -3045,10 +3037,8 @@
EXPORT_PC()
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
- movl $1,%ecx # needed by common_invokeOld - revisit
testl %eax,%eax
- #jne common_invokeMethodRange
- jne common_invokeOld
+ jne common_invokeMethodRange
GET_GLUE(%ecx)
movl offGlue_method(%ecx),%ecx # ecx<- glue->method
movzwl 2(rPC),%eax
@@ -5815,12 +5805,18 @@
/* ------------------------------ */
.balign 64
-.L_OP_UNUSED_ED: /* 0xed */
-/* File: x86/OP_UNUSED_ED.S */
-/* File: x86/unused.S */
- jmp common_abort
-
-
+.L_OP_THROW_VERIFICATION_ERROR: /* 0xed */
+ /* (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_THROW_VERIFICATION_ERROR # 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_EXECUTE_INLINE: /* 0xee */
@@ -6029,9 +6025,8 @@
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
- movl $0,%ecx # pass range flag
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
+
/* ------------------------------ */
@@ -6058,9 +6053,8 @@
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
- movl $1,%ecx # pass range flag
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
+
@@ -6090,9 +6084,7 @@
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
- movl $0,%ecx # ecx<- range flag
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
/* ------------------------------ */
@@ -6122,9 +6114,7 @@
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
- movl $1,%ecx # ecx<- range flag
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
@@ -6407,6 +6397,7 @@
/* continuation for OP_NEW_INSTANCE */
.LOP_NEW_INSTANCE_initialized: # on entry, ecx<- class
+ /* TODO: remove test for interface/abstract, now done in verifier */
testl $(ACC_INTERFACE|ACC_ABSTRACT),offClassObject_accessFlags(%ecx)
movl $ALLOC_DONT_TRACK,OUT_ARG1(%esp)
jne .LOP_NEW_INSTANCE_abstract
@@ -6457,6 +6448,7 @@
jmp common_exceptionThrown # no, handle exception
/*
+ * TODO: remove this
* We can't instantiate an abstract class or interface, so throw an
* InstantiationError with the class descriptor as the message.
*
@@ -7671,9 +7663,7 @@
movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
- movl $0,%ecx # needed for common_invokeOld
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
/* continuation for OP_INVOKE_SUPER */
@@ -7690,9 +7680,8 @@
jae .LOP_INVOKE_SUPER_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
- movl $0,%ecx
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
+
/* At this point:
* ecx = null (needs to be resolved base method)
@@ -7755,10 +7744,8 @@
SPILL(rPC)
call dvmResolveMethod # call(clazz,ref,flags)
UNSPILL(rPC)
- movl $0,%ecx
testl %eax,%eax # got null?
- #jne common_invokeMethodNoRange
- jne common_invokeOld
+ jne common_invokeMethodNoRange
jmp common_exceptionThrown
@@ -7769,9 +7756,7 @@
UNSPILL(rPC)
testl %eax,%eax
je common_exceptionThrown
- movl $0,%ecx
- #jmp common_invokeMethodNoRange
- jmp common_invokeOld
+ jmp common_invokeMethodNoRange
/* continuation for OP_INVOKE_VIRTUAL_RANGE */
@@ -7803,9 +7788,7 @@
movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
- movl $1,%ecx # needed for common_invokeOld
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
/* continuation for OP_INVOKE_SUPER_RANGE */
@@ -7822,9 +7805,8 @@
jae .LOP_INVOKE_SUPER_RANGE_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
- movl $1,%ecx
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
+
/* At this point:
* ecx = null (needs to be resolved base method)
@@ -7887,10 +7869,8 @@
SPILL(rPC)
call dvmResolveMethod # call(clazz,ref,flags)
UNSPILL(rPC)
- movl $1,%ecx
testl %eax,%eax # got null?
- #jne common_invokeMethodRange
- jne common_invokeOld
+ jne common_invokeMethodRange
jmp common_exceptionThrown
@@ -7901,9 +7881,7 @@
UNSPILL(rPC)
testl %eax,%eax
je common_exceptionThrown
- movl $1,%ecx
- #jmp common_invokeMethodRange
- jmp common_invokeOld
+ jmp common_invokeMethodRange
/* continuation for OP_FLOAT_TO_INT */
@@ -8537,11 +8515,217 @@
*/
common_backwardBranch:
GET_GLUE(%ecx)
- call common_periodicChecks # Note: expects rPC to be preserved
+ call common_periodicChecks # Note: expects rPC to be preserved
ADVANCE_PC_INDEXED(rINST_FULL)
FETCH_INST()
GOTO_NEXT
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * eax = Method* methodToCall
+ * rINST trashed, must reload
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+ /*
+ * prepare to copy args to "outs" area of current frame
+ */
+
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- AA
+ movzwl 4(rPC), %ecx # %ecx<- CCCC
+ SPILL(rPC)
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+ test rINST_FULL, rINST_FULL
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
+ jz .LinvokeArgsDone # no args; jump to args done
+
+
+ /*
+ * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
+ * (very few methods have > 10 args; could unroll for common cases)
+ */
+
+ movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
+ lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
+ shll $2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+ subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
+ shrl $2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+1:
+ movl (%ecx), %ebx # %ebx<- vCCCC
+ lea 4(%ecx), %ecx # %ecx<- &vCCCC++
+ subl $1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
+ movl %ebx, (%edx) # *outs<- vCCCC
+ lea 4(%edx), %edx # outs++
+ jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
+ movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
+ jmp .LinvokeArgsDone # continue
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * prepare to copy args to "outs" area of current frame
+ */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- BA
+ SPILL(rPC)
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
+ shrl $4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
+ je .LinvokeArgsDone # no args; jump to args done
+ movzwl 4(rPC), %ecx # %ecx<- GFED
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+
+ /*
+ * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
+ */
+
+.LinvokeNonRange:
+ cmp $2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
+ movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
+ jl 1f # handle 1 arg
+ je 2f # handle 2 args
+ cmp $4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
+ jl 3f # handle 3 args
+ je 4f # handle 4 args
+5:
+ andl $15, rINST_FULL # rINST<- A
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, rINST_FULL, 4), %ecx # %ecx<- vA
+ movl %ecx, (%edx) # *outs<- vA
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+4:
+ shr $12, %ecx # %ecx<- G
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vG
+ movl %ecx, (%edx) # *outs<- vG
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+3:
+ and $0x0f00, %ecx # %ecx<- 0F00
+ shr $8, %ecx # %ecx<- F
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vF
+ movl %ecx, (%edx) # *outs<- vF
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+2:
+ and $0x00f0, %ecx # %ecx<- 00E0
+ shr $4, %ecx # %ecx<- E
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vE
+ movl %ecx, (%edx) # *outs<- vE
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+1:
+ and $0x000f, %ecx # %ecx<- 000D
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vD
+ movl %ecx, -4(%edx) # *--outs<- vD
+0:
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * find space for the new stack frame, check for overflow
+ */
+
+.LinvokeArgsDone:
+ movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
+ movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
+ movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
+ shl $2, %edx # %edx<- update offset
+ SAVEAREA_FROM_FP(%eax,rFP) # %eax<- &StackSaveArea
+ subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
+ GET_GLUE(%edx) # %edx<- pMterpGlue
+ movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
+ subl $sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+ movl offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
+ movl %edx, LOCAL2_OFFSET(%ebp) # LOCAL2_OFFSET<- glue->interpStackEnd
+ shl $2, %ecx # %ecx<- update offset for outsSize
+ movl %eax, %edx # %edx<- newSaveArea
+ sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
+ cmp LOCAL2_OFFSET(%ebp), %eax # compare interpStackEnd and bottom
+ movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
+ jl .LstackOverflow # handle frame overflow
+
+ /*
+ * set up newSaveArea
+ */
+
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(%ecx,rFP) # %ecx<- &StackSaveArea
+ movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+ movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+ movl rPC_SPILL(%ebp), %ecx
+ movl %ecx, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+ testl $ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
+ movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
+ jne .LinvokeNative # handle native call
+
+ /*
+ * Update "glue" values for the new method
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+ */
+
+ movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+ movl %eax, offGlue_method(%ecx) # glue->method<- methodToCall
+ movl %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
+ movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+ movl offGlue_self(%ecx), %eax # %eax<- glue->self
+ movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
+ FETCH_INST()
+ GOTO_NEXT # jump to methodToCall->insns
+
+ /*
+ * Prep for the native call
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
+ */
+
+.LinvokeNative:
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
+ movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
+ movl offThread_jniLocal_nextEntry(%ecx), %eax # %eax<- glue->self->thread->refNext
+ movl %eax, offStackSaveArea_localRefTop(%edx) # newSaveArea->localRefTop<- refNext
+ movl %edx, OUT_ARG4(%esp) # save newSaveArea
+ movl LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
+ movl %edx, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+ movl %ecx, OUT_ARG3(%esp) # save glue->self
+ movl %ecx, OUT_ARG2(%esp) # push parameter glue->self
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl OUT_ARG1(%esp), %eax # %eax<- methodToCall
+ lea offGlue_retval(%ecx), %ecx # %ecx<- &retval
+ movl %ecx, OUT_ARG0(%esp) # push parameter pMterpGlue
+ push %edx # push parameter newFP
+
+ call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+ lea 4(%esp), %esp
+ movl OUT_ARG4(%esp), %ecx # %ecx<- newSaveArea
+ movl OUT_ARG3(%esp), %eax # %eax<- glue->self
+ movl offStackSaveArea_localRefTop(%ecx), %edx # %edx<- newSaveArea->localRefTop
+ cmp $0, offThread_exception(%eax) # check for exception
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+ movl %edx, offThread_jniLocal_nextEntry(%eax) # glue->self<- newSaveArea->localRefTop
+ UNSPILL(rPC)
+ jne common_exceptionThrown # handle exception
+ FETCH_INST_WORD(3)
+ ADVANCE_PC(3)
+ GOTO_NEXT # jump to next instruction
+
+.LstackOverflow:
+ GET_GLUE(%eax) # %eax<- pMterpGlue
+ movl offGlue_self(%eax), %eax # %eax<- glue->self
+ movl %eax, OUT_ARG0(%esp) # push parameter self
+ call dvmHandleStackOverflow # call: (Thread* self)
+ UNSPILL(rPC) # return: void
+ jmp common_exceptionThrown # handle exception
+
+
/*
* Common invoke code (old-style).
* TUNING: Rewrite along lines of new armv5 code?
@@ -8618,6 +8802,7 @@
* bool dvmCheckSuspendPending(Thread* self)
* Because we reached here via a call, go ahead and build a new frame.
*/
+ EXPORT_PC() # need for precise GC
movl offGlue_self(%ecx),%eax # eax<- glue->self
SPILL(rPC) # save edx
push %ebp
diff --git a/vm/mterp/out/InterpC-allstubs.c b/vm/mterp/out/InterpC-allstubs.c
index 635a873..0b70c9e 100644
--- a/vm/mterp/out/InterpC-allstubs.c
+++ b/vm/mterp/out/InterpC-allstubs.c
@@ -26,6 +26,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -53,7 +54,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -93,6 +94,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -116,9 +129,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -303,6 +320,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -316,29 +335,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -402,7 +413,6 @@
return true;
}
-
/* File: cstubs/stubdefs.c */
/* this is a standard (no debug support) interpreter */
#define INTERP_TYPE INTERP_STD
@@ -513,7 +523,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
glue->entryPoint = _entryPoint; \
@@ -1525,9 +1538,7 @@
if (!checkForNullExportPC(obj, fp, pc))
GOTO_exceptionThrown();
ILOGV("+ locking %p %s\n", obj, obj->clazz->descriptor);
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC(); /* need for stack trace */
-#endif
+ EXPORT_PC(); /* need for precise GC, also WITH_MONITOR_TRACKING */
dvmLockObject(self, obj);
#ifdef WITH_DEADLOCK_PREDICTION
if (dvmCheckException(self))
@@ -1674,21 +1685,13 @@
GOTO_exceptionThrown();
/*
- * Note: the verifier can ensure that this never happens, allowing us
- * to remove the check. However, the spec requires we throw the
- * exception at runtime, not verify time, so the verifier would
- * need to replace the new-instance call with a magic "throw
- * InstantiationError" instruction.
- *
- * Since this relies on the verifier, which is optional, we would
- * also need a "new-instance-quick" instruction to identify instances
- * that don't require the check.
+ * Verifier now tests for interface/abstract class.
*/
- if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
- dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
- clazz->descriptor);
- GOTO_exceptionThrown();
- }
+ //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+ // dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
+ // clazz->descriptor);
+ // GOTO_exceptionThrown();
+ //}
newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
if (newObj == NULL)
GOTO_exceptionThrown();
@@ -2784,8 +2787,13 @@
HANDLE_OPCODE(OP_UNUSED_EC)
OP_END
-/* File: c/OP_UNUSED_ED.c */
-HANDLE_OPCODE(OP_UNUSED_ED)
+/* File: c/OP_THROW_VERIFICATION_ERROR.c */
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR)
+ EXPORT_PC();
+ vsrc1 = INST_AA(inst);
+ ref = FETCH(1); /* class/field/method ref */
+ dvmThrowVerificationError(curMethod, vsrc1, ref);
+ GOTO_exceptionThrown();
OP_END
/* File: c/OP_EXECUTE_INLINE.c */
@@ -3861,6 +3869,9 @@
#endif
newSaveArea->prevFrame = fp;
newSaveArea->savedPc = pc;
+#if defined(WITH_JIT)
+ newSaveArea->returnAddr = 0;
+#endif
newSaveArea->method = methodToCall;
if (!dvmIsNativeMethod(methodToCall)) {
@@ -3955,7 +3966,6 @@
assert(false); // should not get here
GOTO_TARGET_END
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
diff --git a/vm/mterp/out/InterpC-armv4t.c b/vm/mterp/out/InterpC-armv4t.c
index 7f101a9..e175560 100644
--- a/vm/mterp/out/InterpC-armv4t.c
+++ b/vm/mterp/out/InterpC-armv4t.c
@@ -26,6 +26,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -53,7 +54,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -93,6 +94,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -116,9 +129,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -303,6 +320,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -316,29 +335,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -402,7 +413,6 @@
return true;
}
-
/* File: cstubs/stubdefs.c */
/* this is a standard (no debug support) interpreter */
#define INTERP_TYPE INTERP_STD
@@ -513,7 +523,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
glue->entryPoint = _entryPoint; \
@@ -1199,17 +1212,17 @@
register uint32_t rPC asm("r4");
register uint32_t rFP asm("r5");
register uint32_t rGLUE asm("r6");
- register uint32_t rIBASE asm("r7");
- register uint32_t rINST asm("r8");
+ register uint32_t rINST asm("r7");
+ register uint32_t rIBASE asm("r8");
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
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 rIBASE=%08x\n",
- rPC, rFP, rGLUE, rIBASE);
- printf(" : rINST=%08x r9=%08x r10=%08x\n", rINST, r9, r10);
+ 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;
@@ -1249,12 +1262,12 @@
* It is a direct (non-virtual) method if it is static, private,
* or a constructor.
*/
- bool isDirect =
+ bool isDirect =
((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
(method->name[0] == '<');
char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
-
+
printf("<%c:%s.%s %s> ",
isDirect ? 'D' : 'V',
method->clazz->descriptor,
diff --git a/vm/mterp/out/InterpC-armv5te-vfp.c b/vm/mterp/out/InterpC-armv5te-vfp.c
new file mode 100644
index 0000000..0065e8e
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv5te-vfp.c
@@ -0,0 +1,1279 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv5te-vfp'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.c */
+/*
+ * 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.
+ */
+
+/* common includes */
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "mterp/Mterp.h"
+#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
+
+/*
+ * Configuration defines. These affect the C implementations, i.e. the
+ * portable interpreter(s) and C stubs.
+ *
+ * Some defines are controlled by the Makefile, e.g.:
+ * WITH_PROFILER
+ * WITH_DEBUGGER
+ * WITH_INSTR_CHECKS
+ * WITH_TRACKREF_CHECKS
+ * EASY_GDB
+ * NDEBUG
+ *
+ * If THREADED_INTERP is not defined, we use a classic "while true / switch"
+ * interpreter. If it is defined, then the tail end of each instruction
+ * handler fetches the next instruction and jumps directly to the handler.
+ * This increases the size of the "Std" interpreter by about 10%, but
+ * provides a speedup of about the same magnitude.
+ *
+ * There's a "hybrid" approach that uses a goto table instead of a switch
+ * statement, avoiding the "is the opcode in range" tests required for switch.
+ * The performance is close to the threaded version, and without the 10%
+ * size increase, but the benchmark results are off enough that it's not
+ * worth adding as a third option.
+ */
+#define THREADED_INTERP /* threaded vs. while-loop interpreter */
+
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * ARM EABI requires 64-bit alignment for access to 64-bit data types. We
+ * can't just use pointers to copy 64-bit values out of our interpreted
+ * register set, because gcc will generate ldrd/strd.
+ *
+ * The __UNION version copies data in and out of a union. The __MEMCPY
+ * version uses a memcpy() call to do the transfer; gcc is smart enough to
+ * not actually call memcpy(). The __UNION version is very bad on ARM;
+ * it only uses one more instruction than __MEMCPY, but for some reason
+ * gcc thinks it needs separate storage for every instance of the union.
+ * On top of that, it feels the need to zero them out at the start of the
+ * method. Net result is we zero out ~700 bytes of stack space at the top
+ * of the interpreter using ARM STM instructions.
+ */
+#if defined(__ARM_EABI__)
+//# define NO_UNALIGN_64__UNION
+# define NO_UNALIGN_64__MEMCPY
+#endif
+
+//#define LOG_INSTR /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * Keep a tally of accesses to fields. Currently only works if full DEX
+ * optimization is disabled.
+ */
+#ifdef PROFILE_FIELD_ACCESS
+# define UPDATE_FIELD_GET(_field) { (_field)->gets++; }
+# define UPDATE_FIELD_PUT(_field) { (_field)->puts++; }
+#else
+# define UPDATE_FIELD_GET(_field) ((void)0)
+# define UPDATE_FIELD_PUT(_field) ((void)0)
+#endif
+
+/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
+ * Adjust the program counter. "_offset" is a signed int, in 16-bit units.
+ *
+ * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
+ *
+ * We don't advance the program counter until we finish an instruction or
+ * branch, because we do want to have to unroll the PC if there's an
+ * exception.
+ */
+#ifdef CHECK_BRANCH_OFFSETS
+# define ADJUST_PC(_offset) do { \
+ int myoff = _offset; /* deref only once */ \
+ if (pc + myoff < curMethod->insns || \
+ pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
+ { \
+ char* desc; \
+ desc = dexProtoCopyMethodDescriptor(&curMethod->prototype); \
+ LOGE("Invalid branch %d at 0x%04x in %s.%s %s\n", \
+ myoff, (int) (pc - curMethod->insns), \
+ curMethod->clazz->descriptor, curMethod->name, desc); \
+ free(desc); \
+ dvmAbort(); \
+ } \
+ pc += myoff; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
+#else
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
+#endif
+
+/*
+ * If enabled, log instructions as we execute them.
+ */
+#ifdef LOG_INSTR
+# define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
+# define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
+# define ILOG(_level, ...) do { \
+ char debugStrBuf[128]; \
+ snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__); \
+ if (curMethod != NULL) \
+ LOG(_level, LOG_TAG"i", "%-2d|%04x%s\n", \
+ self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+ else \
+ LOG(_level, LOG_TAG"i", "%-2d|####%s\n", \
+ self->threadId, debugStrBuf); \
+ } while(false)
+void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
+# define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
+static const char kSpacing[] = " ";
+#else
+# define ILOGD(...) ((void)0)
+# define ILOGV(...) ((void)0)
+# define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
+#endif
+
+/* get a long from an array of u4 */
+static inline s8 getLongFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { s8 ll; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.parts[0] = ptr[0];
+ conv.parts[1] = ptr[1];
+ return conv.ll;
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ s8 val;
+ memcpy(&val, &ptr[idx], 8);
+ return val;
+#else
+ return *((s8*) &ptr[idx]);
+#endif
+}
+
+/* store a long into an array of u4 */
+static inline void putLongToArray(u4* ptr, int idx, s8 val)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { s8 ll; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.ll = val;
+ ptr[0] = conv.parts[0];
+ ptr[1] = conv.parts[1];
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ memcpy(&ptr[idx], &val, 8);
+#else
+ *((s8*) &ptr[idx]) = val;
+#endif
+}
+
+/* get a double from an array of u4 */
+static inline double getDoubleFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { double d; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.parts[0] = ptr[0];
+ conv.parts[1] = ptr[1];
+ return conv.d;
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ double dval;
+ memcpy(&dval, &ptr[idx], 8);
+ return dval;
+#else
+ return *((double*) &ptr[idx]);
+#endif
+}
+
+/* store a double into an array of u4 */
+static inline void putDoubleToArray(u4* ptr, int idx, double dval)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { double d; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.d = dval;
+ ptr[0] = conv.parts[0];
+ ptr[1] = conv.parts[1];
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ memcpy(&ptr[idx], &dval, 8);
+#else
+ *((double*) &ptr[idx]) = dval;
+#endif
+}
+
+/*
+ * If enabled, validate the register number on every access. Otherwise,
+ * just do an array access.
+ *
+ * Assumes the existence of "u4* fp".
+ *
+ * "_idx" may be referenced more than once.
+ */
+#ifdef CHECK_REGISTER_INDICES
+# define GET_REGISTER(_idx) \
+ ( (_idx) < curMethod->registersSize ? \
+ (fp[(_idx)]) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER(_idx, _val) \
+ ( (_idx) < curMethod->registersSize ? \
+ (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_AS_OBJECT(_idx) ((Object *)GET_REGISTER(_idx))
+# define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER_WIDE(_idx, _val) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ putLongToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_FLOAT(_idx) \
+ ( (_idx) < curMethod->registersSize ? \
+ (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
+# define SET_REGISTER_FLOAT(_idx, _val) \
+ ( (_idx) < curMethod->registersSize ? \
+ (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
+# define GET_REGISTER_DOUBLE(_idx) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
+# define SET_REGISTER_DOUBLE(_idx, _val) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ putDoubleToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969.0) )
+#else
+# define GET_REGISTER(_idx) (fp[(_idx)])
+# define SET_REGISTER(_idx, _val) (fp[(_idx)] = (_val))
+# define GET_REGISTER_AS_OBJECT(_idx) ((Object*) fp[(_idx)])
+# define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
+# define GET_REGISTER_INT(_idx) ((s4)GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) getLongFromArray(fp, (_idx))
+# define SET_REGISTER_WIDE(_idx, _val) putLongToArray(fp, (_idx), (_val))
+# define GET_REGISTER_FLOAT(_idx) (*((float*) &fp[(_idx)]))
+# define SET_REGISTER_FLOAT(_idx, _val) (*((float*) &fp[(_idx)]) = (_val))
+# define GET_REGISTER_DOUBLE(_idx) getDoubleFromArray(fp, (_idx))
+# define SET_REGISTER_DOUBLE(_idx, _val) putDoubleToArray(fp, (_idx), (_val))
+#endif
+
+/*
+ * Get 16 bits from the specified offset of the program counter. We always
+ * want to load 16 bits at a time from the instruction stream -- it's more
+ * efficient than 8 and won't have the alignment problems that 32 might.
+ *
+ * Assumes existence of "const u2* pc".
+ */
+#define FETCH(_offset) (pc[(_offset)])
+
+/*
+ * Extract instruction byte from 16-bit fetch (_inst is a u2).
+ */
+#define INST_INST(_inst) ((_inst) & 0xff)
+
+/*
+ * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
+ */
+#define INST_A(_inst) (((_inst) >> 8) & 0x0f)
+#define INST_B(_inst) ((_inst) >> 12)
+
+/*
+ * Get the 8-bit "vAA" 8-bit register index from the instruction word.
+ * (_inst is u2)
+ */
+#define INST_AA(_inst) ((_inst) >> 8)
+
+/*
+ * The current PC must be available to Throwable constructors, e.g.
+ * those created by dvmThrowException(), so that the exception stack
+ * trace can be generated correctly. If we don't do this, the offset
+ * within the current method won't be shown correctly. See the notes
+ * in Exception.c.
+ *
+ * This is also used to determine the address for precise GC.
+ *
+ * Assumes existence of "u4* fp" and "const u2* pc".
+ */
+#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
+
+/*
+ * Determine if we need to switch to a different interpreter. "_current"
+ * is either INTERP_STD or INTERP_DBG. It should be fixed for a given
+ * interpreter generation file, which should remove the outer conditional
+ * from the following.
+ *
+ * If we're building without debug and profiling support, we never switch.
+ */
+#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
+#else
+# define NEED_INTERP_SWITCH(_current) (false)
+#endif
+
+/*
+ * Check to see if "obj" is NULL. If so, throw an exception. Assumes the
+ * pc has already been exported to the stack.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler calls into
+ * something that could throw an exception (so we have already called
+ * EXPORT_PC at the top).
+ */
+static inline bool checkForNull(Object* obj)
+{
+ if (obj == NULL) {
+ dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+ return false;
+ }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+ if (!dvmIsValidObject(obj)) {
+ LOGE("Invalid object %p\n", obj);
+ dvmAbort();
+ }
+#endif
+#ifndef NDEBUG
+ if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+ /* probable heap corruption */
+ LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
+ dvmAbort();
+ }
+#endif
+ return true;
+}
+
+/*
+ * Check to see if "obj" is NULL. If so, export the PC into the stack
+ * frame and throw an exception.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler doesn't do
+ * anything else that can throw an exception.
+ */
+static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
+{
+ if (obj == NULL) {
+ EXPORT_PC();
+ dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+ return false;
+ }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+ if (!dvmIsValidObject(obj)) {
+ LOGE("Invalid object %p\n", obj);
+ dvmAbort();
+ }
+#endif
+#ifndef NDEBUG
+ if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+ /* probable heap corruption */
+ LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
+ dvmAbort();
+ }
+#endif
+ return true;
+}
+
+/* File: cstubs/stubdefs.c */
+/* this is a standard (no debug support) interpreter */
+#define INTERP_TYPE INTERP_STD
+#define CHECK_DEBUG_AND_PROF() ((void)0)
+# define CHECK_TRACKED_REFS() ((void)0)
+
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...) \
+ void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__);
+
+#define GOTO_TARGET(_target, ...) \
+ void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__) { \
+ u2 ref, vsrc1, vsrc2, vdst; \
+ u2 inst = FETCH(0); \
+ const Method* methodToCall; \
+ StackSaveArea* debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into MterpGlue struct
+ * references. (These are undefined down in "footer.c".)
+ */
+#define retval glue->retval
+#define pc glue->pc
+#define fp glue->fp
+#define curMethod glue->method
+#define methodClassDex glue->methodClassDex
+#define self glue->self
+#define debugTrackedRefStart glue->debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+
+
+/*
+ * Opcode handler framing macros. Here, each opcode is a separate function
+ * that takes a "glue" argument and returns void. We can't declare
+ * these "static" because they may be called from an assembly stub.
+ */
+#define HANDLE_OPCODE(_op) \
+ void dvmMterp_##_op(MterpGlue* glue) { \
+ u2 ref, vsrc1, vsrc2, vdst; \
+ u2 inst = FETCH(0);
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.
+ */
+#define FINISH(_offset) { \
+ ADJUST_PC(_offset); \
+ CHECK_DEBUG_AND_PROF(); \
+ CHECK_TRACKED_REFS(); \
+ return; \
+ }
+
+
+/*
+ * The "goto label" statements turn into function calls followed by
+ * return statements. Some of the functions take arguments, which in the
+ * portable interpreter are handled by assigning values to globals.
+ */
+
+#define GOTO_exceptionThrown() \
+ do { \
+ dvmMterp_exceptionThrown(glue); \
+ return; \
+ } while(false)
+
+#define GOTO_returnFromMethod() \
+ do { \
+ dvmMterp_returnFromMethod(glue); \
+ return; \
+ } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange) \
+ do { \
+ dvmMterp_##_target(glue, _methodCallRange); \
+ return; \
+ } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \
+ do { \
+ dvmMterp_invokeMethod(glue, _methodCallRange, _methodToCall, \
+ _vsrc1, _vdst); \
+ return; \
+ } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp. Use "bail_switch"
+ * if we need to switch to the other interpreter upon our return.
+ */
+#define GOTO_bail() \
+ dvmMterpStdBail(glue, false);
+#define GOTO_bail_switch() \
+ dvmMterpStdBail(glue, true);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started. If so, switch to a different "goto" table.
+ */
+#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
+ if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
+ ADJUST_PC(_pcadj); \
+ glue->entryPoint = _entryPoint; \
+ LOGVV("threadid=%d: switch to STD ep=%d adj=%d\n", \
+ glue->self->threadId, (_entryPoint), (_pcadj)); \
+ GOTO_bail_switch(); \
+ } \
+ }
+
+
+/* File: c/opcommon.c */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
+ u2 count, u2 regs);
+GOTO_TARGET_DECL(returnFromMethod);
+GOTO_TARGET_DECL(exceptionThrown);
+
+/*
+ * ===========================================================================
+ *
+ * What follows are opcode definitions shared between multiple opcodes with
+ * minor substitutions handled by the C pre-processor. These should probably
+ * use the mterp substitution mechanism instead, with the code here moved
+ * into common fragment files (like the asm "binop.S"), although it's hard
+ * to give up the C preprocessor in favor of the much simpler text subst.
+ *
+ * ===========================================================================
+ */
+
+#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER##_totype(vdst, \
+ GET_REGISTER##_fromtype(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \
+ _tovtype, _tortype) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ { \
+ /* spec defines specific handling for +/- inf and NaN values */ \
+ _fromvtype val; \
+ _tovtype intMin, intMax, result; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ val = GET_REGISTER##_fromrtype(vsrc1); \
+ intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \
+ intMax = ~intMin; \
+ result = (_tovtype) val; \
+ if (val >= intMax) /* +inf */ \
+ result = intMax; \
+ else if (val <= intMin) /* -inf */ \
+ result = intMin; \
+ else if (val != val) /* NaN */ \
+ result = 0; \
+ else \
+ result = (_tovtype) val; \
+ SET_REGISTER##_tortype(vdst, result); \
+ } \
+ FINISH(1);
+
+#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \
+ FINISH(1);
+
+/* NOTE: the comparison result is always a signed 4-byte integer */
+#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ int result; \
+ u2 regs; \
+ _varType val1, val2; \
+ vdst = INST_AA(inst); \
+ regs = FETCH(1); \
+ vsrc1 = regs & 0xff; \
+ vsrc2 = regs >> 8; \
+ ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ val1 = GET_REGISTER##_type(vsrc1); \
+ val2 = GET_REGISTER##_type(vsrc2); \
+ if (val1 == val2) \
+ result = 0; \
+ else if (val1 < val2) \
+ result = -1; \
+ else if (val1 > val2) \
+ result = 1; \
+ else \
+ result = (_nanVal); \
+ ILOGV("+ result=%d\n", result); \
+ SET_REGISTER(vdst, result); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \
+ HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \
+ vsrc1 = INST_A(inst); \
+ vsrc2 = INST_B(inst); \
+ if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \
+ int branchOffset = (s2)FETCH(1); /* sign-extended */ \
+ ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \
+ branchOffset); \
+ ILOGV("> branch taken"); \
+ if (branchOffset < 0) \
+ PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \
+ FINISH(branchOffset); \
+ } else { \
+ ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \
+ FINISH(2); \
+ }
+
+#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \
+ HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \
+ vsrc1 = INST_AA(inst); \
+ if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \
+ int branchOffset = (s2)FETCH(1); /* sign-extended */ \
+ ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \
+ ILOGV("> branch taken"); \
+ if (branchOffset < 0) \
+ PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \
+ FINISH(branchOffset); \
+ } else { \
+ ILOGV("|if-%s v%d,-", (_opname), vsrc1); \
+ FINISH(2); \
+ }
+
+#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \
+ FINISH(1);
+
+#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ secondVal = GET_REGISTER(vsrc2); \
+ if (secondVal == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ /* non-div/rem case */ \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ vsrc2 = FETCH(1); \
+ ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ if ((s2) vsrc2 == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \
+ /* won't generate /lit16 instr for this; check anyway */ \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op (s2) vsrc2; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ /* non-div/rem case */ \
+ SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
+ { \
+ u2 litInfo; \
+ vdst = INST_AA(inst); \
+ litInfo = FETCH(1); \
+ vsrc1 = litInfo & 0xff; \
+ vsrc2 = litInfo >> 8; /* constant */ \
+ ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ if ((s1) vsrc2 == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op ((s1) vsrc2); \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
+ { \
+ u2 litInfo; \
+ vdst = INST_AA(inst); \
+ litInfo = FETCH(1); \
+ vsrc1 = litInfo & 0xff; \
+ vsrc2 = litInfo >> 8; /* constant */ \
+ ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER(vdst); \
+ secondVal = GET_REGISTER(vsrc1); \
+ if (secondVal == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \
+ } \
+ FINISH(1);
+
+#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s8 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER_WIDE(vsrc1); \
+ secondVal = GET_REGISTER_WIDE(vsrc2); \
+ if (secondVal == 0LL) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u8)firstVal == 0x8000000000000000ULL && \
+ secondVal == -1LL) \
+ { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER_WIDE(vdst, result); \
+ } else { \
+ SET_REGISTER_WIDE(vdst, \
+ (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_WIDE(vdst, \
+ _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s8 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER_WIDE(vdst); \
+ secondVal = GET_REGISTER_WIDE(vsrc1); \
+ if (secondVal == 0LL) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u8)firstVal == 0x8000000000000000ULL && \
+ secondVal == -1LL) \
+ { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER_WIDE(vdst, result); \
+ } else { \
+ SET_REGISTER_WIDE(vdst, \
+ (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
+ } \
+ FINISH(1);
+
+#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_WIDE(vdst, \
+ _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_FLOAT(vdst, \
+ GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_DOUBLE(vdst, \
+ GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_FLOAT(vdst, \
+ GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_DOUBLE(vdst, \
+ GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ ArrayObject* arrayObj; \
+ u2 arrayInfo; \
+ EXPORT_PC(); \
+ vdst = INST_AA(inst); \
+ arrayInfo = FETCH(1); \
+ vsrc1 = arrayInfo & 0xff; /* array ptr */ \
+ vsrc2 = arrayInfo >> 8; /* index */ \
+ ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
+ if (!checkForNull((Object*) arrayObj)) \
+ GOTO_exceptionThrown(); \
+ if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
+ LOGV("Invalid array access: %p %d (len=%d)\n", \
+ arrayObj, vsrc2, arrayObj->length); \
+ dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
+ NULL); \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, \
+ ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)]); \
+ ILOGV("+ AGET[%d]=0x%x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ ArrayObject* arrayObj; \
+ u2 arrayInfo; \
+ EXPORT_PC(); \
+ vdst = INST_AA(inst); /* AA: source value */ \
+ arrayInfo = FETCH(1); \
+ vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \
+ vsrc2 = arrayInfo >> 8; /* CC: index */ \
+ ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
+ if (!checkForNull((Object*) arrayObj)) \
+ GOTO_exceptionThrown(); \
+ if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
+ dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
+ NULL); \
+ GOTO_exceptionThrown(); \
+ } \
+ ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+ ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)] = \
+ GET_REGISTER##_regsize(vdst); \
+ } \
+ FINISH(2);
+
+/*
+ * It's possible to get a bad value out of a field with sub-32-bit stores
+ * because the -quick versions always operate on 32 bits. Consider:
+ * short foo = -1 (sets a 32-bit register to 0xffffffff)
+ * iput-quick foo (writes all 32 bits to the field)
+ * short bar = 1 (sets a 32-bit register to 0x00000001)
+ * iput-short (writes the low 16 bits to the field)
+ * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001)
+ * This can only happen when optimized and non-optimized code has interleaved
+ * access to the same field. This is unlikely but possible.
+ *
+ * The easiest way to fix this is to always read/write 32 bits at a time. On
+ * a device with a 16-bit data bus this is sub-optimal. (The alternative
+ * approach is to have sub-int versions of iget-quick, but now we're wasting
+ * Dalvik instruction space and making it less likely that handler code will
+ * already be in the CPU i-cache.)
+ */
+#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ InstField* ifield; \
+ Object* obj; \
+ EXPORT_PC(); \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNull(obj)) \
+ GOTO_exceptionThrown(); \
+ ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
+ if (ifield == NULL) { \
+ ifield = dvmResolveInstField(curMethod->clazz, ref); \
+ if (ifield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, \
+ dvmGetField##_ftype(obj, ifield->byteOffset)); \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_GET(&ifield->field); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ Object* obj; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field offset */ \
+ ILOGV("|iget%s-quick v%d,v%d,field@+%u", \
+ (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNullExportPC(obj, fp, pc)) \
+ GOTO_exceptionThrown(); \
+ SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \
+ ILOGV("+ IGETQ %d=0x%08llx", ref, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ InstField* ifield; \
+ Object* obj; \
+ EXPORT_PC(); \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNull(obj)) \
+ GOTO_exceptionThrown(); \
+ ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
+ if (ifield == NULL) { \
+ ifield = dvmResolveInstField(curMethod->clazz, ref); \
+ if (ifield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ dvmSetField##_ftype(obj, ifield->byteOffset, \
+ GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_PUT(&ifield->field); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ Object* obj; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field offset */ \
+ ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \
+ (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNullExportPC(obj, fp, pc)) \
+ GOTO_exceptionThrown(); \
+ dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ IPUTQ %d=0x%08llx", ref, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
+ { \
+ StaticField* sfield; \
+ vdst = INST_AA(inst); \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
+ sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+ if (sfield == NULL) { \
+ EXPORT_PC(); \
+ sfield = dvmResolveStaticField(curMethod->clazz, ref); \
+ if (sfield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
+ ILOGV("+ SGET '%s'=0x%08llx", \
+ sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_GET(&sfield->field); \
+ } \
+ FINISH(2);
+
+#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
+ { \
+ StaticField* sfield; \
+ vdst = INST_AA(inst); \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
+ sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+ if (sfield == NULL) { \
+ EXPORT_PC(); \
+ sfield = dvmResolveStaticField(curMethod->clazz, ref); \
+ if (sfield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ SPUT '%s'=0x%08llx", \
+ sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_PUT(&sfield->field); \
+ } \
+ FINISH(2);
+
+
+/* File: cstubs/enddefs.c */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.c */
+#include <inttypes.h>
+
+/*
+ * Dump the fixed-purpose ARM registers, along with some other info.
+ *
+ * This function MUST be compiled in ARM mode -- THUMB will yield bogus
+ * results.
+ *
+ * This will NOT preserve r0-r3/ip.
+ */
+void dvmMterpDumpArmRegs(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3)
+{
+ register uint32_t rPC asm("r4");
+ register uint32_t rFP asm("r5");
+ register uint32_t rGLUE asm("r6");
+ register uint32_t rINST asm("r7");
+ register uint32_t rIBASE asm("r8");
+ register uint32_t r9 asm("r9");
+ register uint32_t r10 asm("r10");
+
+ 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;
+ printf(" + self is %p\n", dvmThreadSelf());
+ //printf(" + currently in %s.%s %s\n",
+ // method->clazz->descriptor, method->name, method->signature);
+ //printf(" + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
+ //printf(" + next handler for 0x%02x = %p\n",
+ // rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
+}
+
+/*
+ * Dump the StackSaveArea for the specified frame pointer.
+ */
+void dvmDumpFp(void* fp, StackSaveArea* otherSaveArea)
+{
+ StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+ printf("StackSaveArea for fp %p [%p/%p]:\n", fp, saveArea, otherSaveArea);
+#ifdef EASY_GDB
+ printf(" prevSave=%p, prevFrame=%p savedPc=%p meth=%p curPc=%p\n",
+ saveArea->prevSave, saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc);
+#else
+ printf(" prevFrame=%p savedPc=%p meth=%p curPc=%p fp[0]=0x%08x\n",
+ saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc,
+ *(u4*)fp);
+#endif
+}
+
+/*
+ * Does the bulk of the work for common_printMethod().
+ */
+void dvmMterpPrintMethod(Method* method)
+{
+ /*
+ * It is a direct (non-virtual) method if it is static, private,
+ * or a constructor.
+ */
+ bool isDirect =
+ ((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
+ (method->name[0] == '<');
+
+ char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+
+ printf("<%c:%s.%s %s> ",
+ isDirect ? 'D' : 'V',
+ method->clazz->descriptor,
+ method->name,
+ desc);
+
+ free(desc);
+}
+
diff --git a/vm/mterp/out/InterpC-armv5te.c b/vm/mterp/out/InterpC-armv5te.c
index 47c8709..d3b6871 100644
--- a/vm/mterp/out/InterpC-armv5te.c
+++ b/vm/mterp/out/InterpC-armv5te.c
@@ -26,6 +26,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -53,7 +54,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -93,6 +94,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -116,9 +129,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -303,6 +320,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -316,29 +335,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -402,7 +413,6 @@
return true;
}
-
/* File: cstubs/stubdefs.c */
/* this is a standard (no debug support) interpreter */
#define INTERP_TYPE INTERP_STD
@@ -513,7 +523,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
glue->entryPoint = _entryPoint; \
@@ -1199,17 +1212,17 @@
register uint32_t rPC asm("r4");
register uint32_t rFP asm("r5");
register uint32_t rGLUE asm("r6");
- register uint32_t rIBASE asm("r7");
- register uint32_t rINST asm("r8");
+ register uint32_t rINST asm("r7");
+ register uint32_t rIBASE asm("r8");
register uint32_t r9 asm("r9");
register uint32_t r10 asm("r10");
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 rIBASE=%08x\n",
- rPC, rFP, rGLUE, rIBASE);
- printf(" : rINST=%08x r9=%08x r10=%08x\n", rINST, r9, r10);
+ 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;
@@ -1249,12 +1262,12 @@
* It is a direct (non-virtual) method if it is static, private,
* or a constructor.
*/
- bool isDirect =
+ bool isDirect =
((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
(method->name[0] == '<');
char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
-
+
printf("<%c:%s.%s %s> ",
isDirect ? 'D' : 'V',
method->clazz->descriptor,
diff --git a/vm/mterp/out/InterpC-armv7-a.c b/vm/mterp/out/InterpC-armv7-a.c
new file mode 100644
index 0000000..4fcfd6a
--- /dev/null
+++ b/vm/mterp/out/InterpC-armv7-a.c
@@ -0,0 +1,1279 @@
+/*
+ * This file was generated automatically by gen-mterp.py for 'armv7-a'.
+ *
+ * --> DO NOT EDIT <--
+ */
+
+/* File: c/header.c */
+/*
+ * 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.
+ */
+
+/* common includes */
+#include "Dalvik.h"
+#include "interp/InterpDefs.h"
+#include "mterp/Mterp.h"
+#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
+
+/*
+ * Configuration defines. These affect the C implementations, i.e. the
+ * portable interpreter(s) and C stubs.
+ *
+ * Some defines are controlled by the Makefile, e.g.:
+ * WITH_PROFILER
+ * WITH_DEBUGGER
+ * WITH_INSTR_CHECKS
+ * WITH_TRACKREF_CHECKS
+ * EASY_GDB
+ * NDEBUG
+ *
+ * If THREADED_INTERP is not defined, we use a classic "while true / switch"
+ * interpreter. If it is defined, then the tail end of each instruction
+ * handler fetches the next instruction and jumps directly to the handler.
+ * This increases the size of the "Std" interpreter by about 10%, but
+ * provides a speedup of about the same magnitude.
+ *
+ * There's a "hybrid" approach that uses a goto table instead of a switch
+ * statement, avoiding the "is the opcode in range" tests required for switch.
+ * The performance is close to the threaded version, and without the 10%
+ * size increase, but the benchmark results are off enough that it's not
+ * worth adding as a third option.
+ */
+#define THREADED_INTERP /* threaded vs. while-loop interpreter */
+
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
+# define CHECK_BRANCH_OFFSETS
+# define CHECK_REGISTER_INDICES
+#endif
+
+/*
+ * ARM EABI requires 64-bit alignment for access to 64-bit data types. We
+ * can't just use pointers to copy 64-bit values out of our interpreted
+ * register set, because gcc will generate ldrd/strd.
+ *
+ * The __UNION version copies data in and out of a union. The __MEMCPY
+ * version uses a memcpy() call to do the transfer; gcc is smart enough to
+ * not actually call memcpy(). The __UNION version is very bad on ARM;
+ * it only uses one more instruction than __MEMCPY, but for some reason
+ * gcc thinks it needs separate storage for every instance of the union.
+ * On top of that, it feels the need to zero them out at the start of the
+ * method. Net result is we zero out ~700 bytes of stack space at the top
+ * of the interpreter using ARM STM instructions.
+ */
+#if defined(__ARM_EABI__)
+//# define NO_UNALIGN_64__UNION
+# define NO_UNALIGN_64__MEMCPY
+#endif
+
+//#define LOG_INSTR /* verbose debugging */
+/* set and adjust ANDROID_LOG_TAGS='*:i jdwp:i dalvikvm:i dalvikvmi:i' */
+
+/*
+ * Keep a tally of accesses to fields. Currently only works if full DEX
+ * optimization is disabled.
+ */
+#ifdef PROFILE_FIELD_ACCESS
+# define UPDATE_FIELD_GET(_field) { (_field)->gets++; }
+# define UPDATE_FIELD_PUT(_field) { (_field)->puts++; }
+#else
+# define UPDATE_FIELD_GET(_field) ((void)0)
+# define UPDATE_FIELD_PUT(_field) ((void)0)
+#endif
+
+/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
+ * Adjust the program counter. "_offset" is a signed int, in 16-bit units.
+ *
+ * Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
+ *
+ * We don't advance the program counter until we finish an instruction or
+ * branch, because we do want to have to unroll the PC if there's an
+ * exception.
+ */
+#ifdef CHECK_BRANCH_OFFSETS
+# define ADJUST_PC(_offset) do { \
+ int myoff = _offset; /* deref only once */ \
+ if (pc + myoff < curMethod->insns || \
+ pc + myoff >= curMethod->insns + dvmGetMethodInsnsSize(curMethod)) \
+ { \
+ char* desc; \
+ desc = dexProtoCopyMethodDescriptor(&curMethod->prototype); \
+ LOGE("Invalid branch %d at 0x%04x in %s.%s %s\n", \
+ myoff, (int) (pc - curMethod->insns), \
+ curMethod->clazz->descriptor, curMethod->name, desc); \
+ free(desc); \
+ dvmAbort(); \
+ } \
+ pc += myoff; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
+#else
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
+#endif
+
+/*
+ * If enabled, log instructions as we execute them.
+ */
+#ifdef LOG_INSTR
+# define ILOGD(...) ILOG(LOG_DEBUG, __VA_ARGS__)
+# define ILOGV(...) ILOG(LOG_VERBOSE, __VA_ARGS__)
+# define ILOG(_level, ...) do { \
+ char debugStrBuf[128]; \
+ snprintf(debugStrBuf, sizeof(debugStrBuf), __VA_ARGS__); \
+ if (curMethod != NULL) \
+ LOG(_level, LOG_TAG"i", "%-2d|%04x%s\n", \
+ self->threadId, (int)(pc - curMethod->insns), debugStrBuf); \
+ else \
+ LOG(_level, LOG_TAG"i", "%-2d|####%s\n", \
+ self->threadId, debugStrBuf); \
+ } while(false)
+void dvmDumpRegs(const Method* method, const u4* framePtr, bool inOnly);
+# define DUMP_REGS(_meth, _frame, _inOnly) dvmDumpRegs(_meth, _frame, _inOnly)
+static const char kSpacing[] = " ";
+#else
+# define ILOGD(...) ((void)0)
+# define ILOGV(...) ((void)0)
+# define DUMP_REGS(_meth, _frame, _inOnly) ((void)0)
+#endif
+
+/* get a long from an array of u4 */
+static inline s8 getLongFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { s8 ll; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.parts[0] = ptr[0];
+ conv.parts[1] = ptr[1];
+ return conv.ll;
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ s8 val;
+ memcpy(&val, &ptr[idx], 8);
+ return val;
+#else
+ return *((s8*) &ptr[idx]);
+#endif
+}
+
+/* store a long into an array of u4 */
+static inline void putLongToArray(u4* ptr, int idx, s8 val)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { s8 ll; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.ll = val;
+ ptr[0] = conv.parts[0];
+ ptr[1] = conv.parts[1];
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ memcpy(&ptr[idx], &val, 8);
+#else
+ *((s8*) &ptr[idx]) = val;
+#endif
+}
+
+/* get a double from an array of u4 */
+static inline double getDoubleFromArray(const u4* ptr, int idx)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { double d; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.parts[0] = ptr[0];
+ conv.parts[1] = ptr[1];
+ return conv.d;
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ double dval;
+ memcpy(&dval, &ptr[idx], 8);
+ return dval;
+#else
+ return *((double*) &ptr[idx]);
+#endif
+}
+
+/* store a double into an array of u4 */
+static inline void putDoubleToArray(u4* ptr, int idx, double dval)
+{
+#if defined(NO_UNALIGN_64__UNION)
+ union { double d; u4 parts[2]; } conv;
+
+ ptr += idx;
+ conv.d = dval;
+ ptr[0] = conv.parts[0];
+ ptr[1] = conv.parts[1];
+#elif defined(NO_UNALIGN_64__MEMCPY)
+ memcpy(&ptr[idx], &dval, 8);
+#else
+ *((double*) &ptr[idx]) = dval;
+#endif
+}
+
+/*
+ * If enabled, validate the register number on every access. Otherwise,
+ * just do an array access.
+ *
+ * Assumes the existence of "u4* fp".
+ *
+ * "_idx" may be referenced more than once.
+ */
+#ifdef CHECK_REGISTER_INDICES
+# define GET_REGISTER(_idx) \
+ ( (_idx) < curMethod->registersSize ? \
+ (fp[(_idx)]) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER(_idx, _val) \
+ ( (_idx) < curMethod->registersSize ? \
+ (fp[(_idx)] = (u4)(_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_AS_OBJECT(_idx) ((Object *)GET_REGISTER(_idx))
+# define SET_REGISTER_AS_OBJECT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_INT(_idx) ((s4) GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ getLongFromArray(fp, (_idx)) : (assert(!"bad reg"),1969) )
+# define SET_REGISTER_WIDE(_idx, _val) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ putLongToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969) )
+# define GET_REGISTER_FLOAT(_idx) \
+ ( (_idx) < curMethod->registersSize ? \
+ (*((float*) &fp[(_idx)])) : (assert(!"bad reg"),1969.0f) )
+# define SET_REGISTER_FLOAT(_idx, _val) \
+ ( (_idx) < curMethod->registersSize ? \
+ (*((float*) &fp[(_idx)]) = (_val)) : (assert(!"bad reg"),1969.0f) )
+# define GET_REGISTER_DOUBLE(_idx) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ getDoubleFromArray(fp, (_idx)) : (assert(!"bad reg"),1969.0) )
+# define SET_REGISTER_DOUBLE(_idx, _val) \
+ ( (_idx) < curMethod->registersSize-1 ? \
+ putDoubleToArray(fp, (_idx), (_val)) : (assert(!"bad reg"),1969.0) )
+#else
+# define GET_REGISTER(_idx) (fp[(_idx)])
+# define SET_REGISTER(_idx, _val) (fp[(_idx)] = (_val))
+# define GET_REGISTER_AS_OBJECT(_idx) ((Object*) fp[(_idx)])
+# define SET_REGISTER_AS_OBJECT(_idx, _val) (fp[(_idx)] = (u4)(_val))
+# define GET_REGISTER_INT(_idx) ((s4)GET_REGISTER(_idx))
+# define SET_REGISTER_INT(_idx, _val) SET_REGISTER(_idx, (s4)_val)
+# define GET_REGISTER_WIDE(_idx) getLongFromArray(fp, (_idx))
+# define SET_REGISTER_WIDE(_idx, _val) putLongToArray(fp, (_idx), (_val))
+# define GET_REGISTER_FLOAT(_idx) (*((float*) &fp[(_idx)]))
+# define SET_REGISTER_FLOAT(_idx, _val) (*((float*) &fp[(_idx)]) = (_val))
+# define GET_REGISTER_DOUBLE(_idx) getDoubleFromArray(fp, (_idx))
+# define SET_REGISTER_DOUBLE(_idx, _val) putDoubleToArray(fp, (_idx), (_val))
+#endif
+
+/*
+ * Get 16 bits from the specified offset of the program counter. We always
+ * want to load 16 bits at a time from the instruction stream -- it's more
+ * efficient than 8 and won't have the alignment problems that 32 might.
+ *
+ * Assumes existence of "const u2* pc".
+ */
+#define FETCH(_offset) (pc[(_offset)])
+
+/*
+ * Extract instruction byte from 16-bit fetch (_inst is a u2).
+ */
+#define INST_INST(_inst) ((_inst) & 0xff)
+
+/*
+ * Extract the "vA, vB" 4-bit registers from the instruction word (_inst is u2).
+ */
+#define INST_A(_inst) (((_inst) >> 8) & 0x0f)
+#define INST_B(_inst) ((_inst) >> 12)
+
+/*
+ * Get the 8-bit "vAA" 8-bit register index from the instruction word.
+ * (_inst is u2)
+ */
+#define INST_AA(_inst) ((_inst) >> 8)
+
+/*
+ * The current PC must be available to Throwable constructors, e.g.
+ * those created by dvmThrowException(), so that the exception stack
+ * trace can be generated correctly. If we don't do this, the offset
+ * within the current method won't be shown correctly. See the notes
+ * in Exception.c.
+ *
+ * This is also used to determine the address for precise GC.
+ *
+ * Assumes existence of "u4* fp" and "const u2* pc".
+ */
+#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
+
+/*
+ * Determine if we need to switch to a different interpreter. "_current"
+ * is either INTERP_STD or INTERP_DBG. It should be fixed for a given
+ * interpreter generation file, which should remove the outer conditional
+ * from the following.
+ *
+ * If we're building without debug and profiling support, we never switch.
+ */
+#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
+#else
+# define NEED_INTERP_SWITCH(_current) (false)
+#endif
+
+/*
+ * Check to see if "obj" is NULL. If so, throw an exception. Assumes the
+ * pc has already been exported to the stack.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler calls into
+ * something that could throw an exception (so we have already called
+ * EXPORT_PC at the top).
+ */
+static inline bool checkForNull(Object* obj)
+{
+ if (obj == NULL) {
+ dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+ return false;
+ }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+ if (!dvmIsValidObject(obj)) {
+ LOGE("Invalid object %p\n", obj);
+ dvmAbort();
+ }
+#endif
+#ifndef NDEBUG
+ if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+ /* probable heap corruption */
+ LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
+ dvmAbort();
+ }
+#endif
+ return true;
+}
+
+/*
+ * Check to see if "obj" is NULL. If so, export the PC into the stack
+ * frame and throw an exception.
+ *
+ * Perform additional checks on debug builds.
+ *
+ * Use this to check for NULL when the instruction handler doesn't do
+ * anything else that can throw an exception.
+ */
+static inline bool checkForNullExportPC(Object* obj, u4* fp, const u2* pc)
+{
+ if (obj == NULL) {
+ EXPORT_PC();
+ dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+ return false;
+ }
+#ifdef WITH_EXTRA_OBJECT_VALIDATION
+ if (!dvmIsValidObject(obj)) {
+ LOGE("Invalid object %p\n", obj);
+ dvmAbort();
+ }
+#endif
+#ifndef NDEBUG
+ if (obj->clazz == NULL || ((u4) obj->clazz) <= 65536) {
+ /* probable heap corruption */
+ LOGE("Invalid object class %p (in %p)\n", obj->clazz, obj);
+ dvmAbort();
+ }
+#endif
+ return true;
+}
+
+/* File: cstubs/stubdefs.c */
+/* this is a standard (no debug support) interpreter */
+#define INTERP_TYPE INTERP_STD
+#define CHECK_DEBUG_AND_PROF() ((void)0)
+# define CHECK_TRACKED_REFS() ((void)0)
+
+/*
+ * In the C mterp stubs, "goto" is a function call followed immediately
+ * by a return.
+ */
+
+#define GOTO_TARGET_DECL(_target, ...) \
+ void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__);
+
+#define GOTO_TARGET(_target, ...) \
+ void dvmMterp_##_target(MterpGlue* glue, ## __VA_ARGS__) { \
+ u2 ref, vsrc1, vsrc2, vdst; \
+ u2 inst = FETCH(0); \
+ const Method* methodToCall; \
+ StackSaveArea* debugSaveArea;
+
+#define GOTO_TARGET_END }
+
+/*
+ * Redefine what used to be local variable accesses into MterpGlue struct
+ * references. (These are undefined down in "footer.c".)
+ */
+#define retval glue->retval
+#define pc glue->pc
+#define fp glue->fp
+#define curMethod glue->method
+#define methodClassDex glue->methodClassDex
+#define self glue->self
+#define debugTrackedRefStart glue->debugTrackedRefStart
+
+/* ugh */
+#define STUB_HACK(x) x
+
+
+/*
+ * Opcode handler framing macros. Here, each opcode is a separate function
+ * that takes a "glue" argument and returns void. We can't declare
+ * these "static" because they may be called from an assembly stub.
+ */
+#define HANDLE_OPCODE(_op) \
+ void dvmMterp_##_op(MterpGlue* glue) { \
+ u2 ref, vsrc1, vsrc2, vdst; \
+ u2 inst = FETCH(0);
+
+#define OP_END }
+
+/*
+ * Like the "portable" FINISH, but don't reload "inst", and return to caller
+ * when done.
+ */
+#define FINISH(_offset) { \
+ ADJUST_PC(_offset); \
+ CHECK_DEBUG_AND_PROF(); \
+ CHECK_TRACKED_REFS(); \
+ return; \
+ }
+
+
+/*
+ * The "goto label" statements turn into function calls followed by
+ * return statements. Some of the functions take arguments, which in the
+ * portable interpreter are handled by assigning values to globals.
+ */
+
+#define GOTO_exceptionThrown() \
+ do { \
+ dvmMterp_exceptionThrown(glue); \
+ return; \
+ } while(false)
+
+#define GOTO_returnFromMethod() \
+ do { \
+ dvmMterp_returnFromMethod(glue); \
+ return; \
+ } while(false)
+
+#define GOTO_invoke(_target, _methodCallRange) \
+ do { \
+ dvmMterp_##_target(glue, _methodCallRange); \
+ return; \
+ } while(false)
+
+#define GOTO_invokeMethod(_methodCallRange, _methodToCall, _vsrc1, _vdst) \
+ do { \
+ dvmMterp_invokeMethod(glue, _methodCallRange, _methodToCall, \
+ _vsrc1, _vdst); \
+ return; \
+ } while(false)
+
+/*
+ * As a special case, "goto bail" turns into a longjmp. Use "bail_switch"
+ * if we need to switch to the other interpreter upon our return.
+ */
+#define GOTO_bail() \
+ dvmMterpStdBail(glue, false);
+#define GOTO_bail_switch() \
+ dvmMterpStdBail(glue, true);
+
+/*
+ * Periodically check for thread suspension.
+ *
+ * While we're at it, see if a debugger has attached or the profiler has
+ * started. If so, switch to a different "goto" table.
+ */
+#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
+ if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
+ ADJUST_PC(_pcadj); \
+ glue->entryPoint = _entryPoint; \
+ LOGVV("threadid=%d: switch to STD ep=%d adj=%d\n", \
+ glue->self->threadId, (_entryPoint), (_pcadj)); \
+ GOTO_bail_switch(); \
+ } \
+ }
+
+
+/* File: c/opcommon.c */
+/* forward declarations of goto targets */
+GOTO_TARGET_DECL(filledNewArray, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtual, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuper, bool methodCallRange);
+GOTO_TARGET_DECL(invokeInterface, bool methodCallRange);
+GOTO_TARGET_DECL(invokeDirect, bool methodCallRange);
+GOTO_TARGET_DECL(invokeStatic, bool methodCallRange);
+GOTO_TARGET_DECL(invokeVirtualQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeSuperQuick, bool methodCallRange);
+GOTO_TARGET_DECL(invokeMethod, bool methodCallRange, const Method* methodToCall,
+ u2 count, u2 regs);
+GOTO_TARGET_DECL(returnFromMethod);
+GOTO_TARGET_DECL(exceptionThrown);
+
+/*
+ * ===========================================================================
+ *
+ * What follows are opcode definitions shared between multiple opcodes with
+ * minor substitutions handled by the C pre-processor. These should probably
+ * use the mterp substitution mechanism instead, with the code here moved
+ * into common fragment files (like the asm "binop.S"), although it's hard
+ * to give up the C preprocessor in favor of the much simpler text subst.
+ *
+ * ===========================================================================
+ */
+
+#define HANDLE_NUMCONV(_opcode, _opname, _fromtype, _totype) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER##_totype(vdst, \
+ GET_REGISTER##_fromtype(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_FLOAT_TO_INT(_opcode, _opname, _fromvtype, _fromrtype, \
+ _tovtype, _tortype) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ { \
+ /* spec defines specific handling for +/- inf and NaN values */ \
+ _fromvtype val; \
+ _tovtype intMin, intMax, result; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ val = GET_REGISTER##_fromrtype(vsrc1); \
+ intMin = (_tovtype) 1 << (sizeof(_tovtype) * 8 -1); \
+ intMax = ~intMin; \
+ result = (_tovtype) val; \
+ if (val >= intMax) /* +inf */ \
+ result = intMax; \
+ else if (val <= intMin) /* -inf */ \
+ result = intMin; \
+ else if (val != val) /* NaN */ \
+ result = 0; \
+ else \
+ result = (_tovtype) val; \
+ SET_REGISTER##_tortype(vdst, result); \
+ } \
+ FINISH(1);
+
+#define HANDLE_INT_TO_SMALL(_opcode, _opname, _type) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|int-to-%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, (_type) GET_REGISTER(vsrc1)); \
+ FINISH(1);
+
+/* NOTE: the comparison result is always a signed 4-byte integer */
+#define HANDLE_OP_CMPX(_opcode, _opname, _varType, _type, _nanVal) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ int result; \
+ u2 regs; \
+ _varType val1, val2; \
+ vdst = INST_AA(inst); \
+ regs = FETCH(1); \
+ vsrc1 = regs & 0xff; \
+ vsrc2 = regs >> 8; \
+ ILOGV("|cmp%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ val1 = GET_REGISTER##_type(vsrc1); \
+ val2 = GET_REGISTER##_type(vsrc2); \
+ if (val1 == val2) \
+ result = 0; \
+ else if (val1 < val2) \
+ result = -1; \
+ else if (val1 > val2) \
+ result = 1; \
+ else \
+ result = (_nanVal); \
+ ILOGV("+ result=%d\n", result); \
+ SET_REGISTER(vdst, result); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_IF_XX(_opcode, _opname, _cmp) \
+ HANDLE_OPCODE(_opcode /*vA, vB, +CCCC*/) \
+ vsrc1 = INST_A(inst); \
+ vsrc2 = INST_B(inst); \
+ if ((s4) GET_REGISTER(vsrc1) _cmp (s4) GET_REGISTER(vsrc2)) { \
+ int branchOffset = (s2)FETCH(1); /* sign-extended */ \
+ ILOGV("|if-%s v%d,v%d,+0x%04x", (_opname), vsrc1, vsrc2, \
+ branchOffset); \
+ ILOGV("> branch taken"); \
+ if (branchOffset < 0) \
+ PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \
+ FINISH(branchOffset); \
+ } else { \
+ ILOGV("|if-%s v%d,v%d,-", (_opname), vsrc1, vsrc2); \
+ FINISH(2); \
+ }
+
+#define HANDLE_OP_IF_XXZ(_opcode, _opname, _cmp) \
+ HANDLE_OPCODE(_opcode /*vAA, +BBBB*/) \
+ vsrc1 = INST_AA(inst); \
+ if ((s4) GET_REGISTER(vsrc1) _cmp 0) { \
+ int branchOffset = (s2)FETCH(1); /* sign-extended */ \
+ ILOGV("|if-%s v%d,+0x%04x", (_opname), vsrc1, branchOffset); \
+ ILOGV("> branch taken"); \
+ if (branchOffset < 0) \
+ PERIODIC_CHECKS(kInterpEntryInstr, branchOffset); \
+ FINISH(branchOffset); \
+ } else { \
+ ILOGV("|if-%s v%d,-", (_opname), vsrc1); \
+ FINISH(2); \
+ }
+
+#define HANDLE_UNOP(_opcode, _opname, _pfx, _sfx, _type) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER##_type(vdst, _pfx GET_REGISTER##_type(vsrc1) _sfx); \
+ FINISH(1);
+
+#define HANDLE_OP_X_INT(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ secondVal = GET_REGISTER(vsrc2); \
+ if (secondVal == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ /* non-div/rem case */ \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vsrc1) _op (s4) GET_REGISTER(vsrc2)); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_INT(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-int v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vsrc1) _op (GET_REGISTER(vsrc2) & 0x1f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT16(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB, #+CCCC*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ vsrc2 = FETCH(1); \
+ ILOGV("|%s-int/lit16 v%d,v%d,#+0x%04x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ if ((s2) vsrc2 == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && ((s2) vsrc2) == -1) { \
+ /* won't generate /lit16 instr for this; check anyway */ \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op (s2) vsrc2; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ /* non-div/rem case */ \
+ SET_REGISTER(vdst, GET_REGISTER(vsrc1) _op (s2) vsrc2); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_LIT8(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
+ { \
+ u2 litInfo; \
+ vdst = INST_AA(inst); \
+ litInfo = FETCH(1); \
+ vsrc1 = litInfo & 0xff; \
+ vsrc2 = litInfo >> 8; /* constant */ \
+ ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, result; \
+ firstVal = GET_REGISTER(vsrc1); \
+ if ((s1) vsrc2 == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && ((s1) vsrc2) == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op ((s1) vsrc2); \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vsrc1) _op (s1) vsrc2); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_INT_LIT8(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, #+CC*/) \
+ { \
+ u2 litInfo; \
+ vdst = INST_AA(inst); \
+ litInfo = FETCH(1); \
+ vsrc1 = litInfo & 0xff; \
+ vsrc2 = litInfo >> 8; /* constant */ \
+ ILOGV("|%s-int/lit8 v%d,v%d,#+0x%02x", \
+ (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vsrc1) _op (vsrc2 & 0x1f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_INT_2ADDR(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s4 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER(vdst); \
+ secondVal = GET_REGISTER(vsrc1); \
+ if (secondVal == 0) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u4)firstVal == 0x80000000 && secondVal == -1) { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER(vdst, result); \
+ } else { \
+ SET_REGISTER(vdst, \
+ (s4) GET_REGISTER(vdst) _op (s4) GET_REGISTER(vsrc1)); \
+ } \
+ FINISH(1);
+
+#define HANDLE_OP_SHX_INT_2ADDR(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-int-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER(vdst, \
+ _cast GET_REGISTER(vdst) _op (GET_REGISTER(vsrc1) & 0x1f)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_LONG(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ if (_chkdiv != 0) { \
+ s8 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER_WIDE(vsrc1); \
+ secondVal = GET_REGISTER_WIDE(vsrc2); \
+ if (secondVal == 0LL) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u8)firstVal == 0x8000000000000000ULL && \
+ secondVal == -1LL) \
+ { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER_WIDE(vdst, result); \
+ } else { \
+ SET_REGISTER_WIDE(vdst, \
+ (s8) GET_REGISTER_WIDE(vsrc1) _op (s8) GET_REGISTER_WIDE(vsrc2)); \
+ } \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_SHX_LONG(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-long v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_WIDE(vdst, \
+ _cast GET_REGISTER_WIDE(vsrc1) _op (GET_REGISTER(vsrc2) & 0x3f)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_LONG_2ADDR(_opcode, _opname, _op, _chkdiv) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ if (_chkdiv != 0) { \
+ s8 firstVal, secondVal, result; \
+ firstVal = GET_REGISTER_WIDE(vdst); \
+ secondVal = GET_REGISTER_WIDE(vsrc1); \
+ if (secondVal == 0LL) { \
+ EXPORT_PC(); \
+ dvmThrowException("Ljava/lang/ArithmeticException;", \
+ "divide by zero"); \
+ GOTO_exceptionThrown(); \
+ } \
+ if ((u8)firstVal == 0x8000000000000000ULL && \
+ secondVal == -1LL) \
+ { \
+ if (_chkdiv == 1) \
+ result = firstVal; /* division */ \
+ else \
+ result = 0; /* remainder */ \
+ } else { \
+ result = firstVal _op secondVal; \
+ } \
+ SET_REGISTER_WIDE(vdst, result); \
+ } else { \
+ SET_REGISTER_WIDE(vdst, \
+ (s8) GET_REGISTER_WIDE(vdst) _op (s8)GET_REGISTER_WIDE(vsrc1));\
+ } \
+ FINISH(1);
+
+#define HANDLE_OP_SHX_LONG_2ADDR(_opcode, _opname, _cast, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-long-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_WIDE(vdst, \
+ _cast GET_REGISTER_WIDE(vdst) _op (GET_REGISTER(vsrc1) & 0x3f)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_FLOAT(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-float v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_FLOAT(vdst, \
+ GET_REGISTER_FLOAT(vsrc1) _op GET_REGISTER_FLOAT(vsrc2)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_DOUBLE(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ u2 srcRegs; \
+ vdst = INST_AA(inst); \
+ srcRegs = FETCH(1); \
+ vsrc1 = srcRegs & 0xff; \
+ vsrc2 = srcRegs >> 8; \
+ ILOGV("|%s-double v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ SET_REGISTER_DOUBLE(vdst, \
+ GET_REGISTER_DOUBLE(vsrc1) _op GET_REGISTER_DOUBLE(vsrc2)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_X_FLOAT_2ADDR(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-float-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_FLOAT(vdst, \
+ GET_REGISTER_FLOAT(vdst) _op GET_REGISTER_FLOAT(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_OP_X_DOUBLE_2ADDR(_opcode, _opname, _op) \
+ HANDLE_OPCODE(_opcode /*vA, vB*/) \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); \
+ ILOGV("|%s-double-2addr v%d,v%d", (_opname), vdst, vsrc1); \
+ SET_REGISTER_DOUBLE(vdst, \
+ GET_REGISTER_DOUBLE(vdst) _op GET_REGISTER_DOUBLE(vsrc1)); \
+ FINISH(1);
+
+#define HANDLE_OP_AGET(_opcode, _opname, _type, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ ArrayObject* arrayObj; \
+ u2 arrayInfo; \
+ EXPORT_PC(); \
+ vdst = INST_AA(inst); \
+ arrayInfo = FETCH(1); \
+ vsrc1 = arrayInfo & 0xff; /* array ptr */ \
+ vsrc2 = arrayInfo >> 8; /* index */ \
+ ILOGV("|aget%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
+ if (!checkForNull((Object*) arrayObj)) \
+ GOTO_exceptionThrown(); \
+ if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
+ LOGV("Invalid array access: %p %d (len=%d)\n", \
+ arrayObj, vsrc2, arrayObj->length); \
+ dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
+ NULL); \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, \
+ ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)]); \
+ ILOGV("+ AGET[%d]=0x%x", GET_REGISTER(vsrc2), GET_REGISTER(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_OP_APUT(_opcode, _opname, _type, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, vBB, vCC*/) \
+ { \
+ ArrayObject* arrayObj; \
+ u2 arrayInfo; \
+ EXPORT_PC(); \
+ vdst = INST_AA(inst); /* AA: source value */ \
+ arrayInfo = FETCH(1); \
+ vsrc1 = arrayInfo & 0xff; /* BB: array ptr */ \
+ vsrc2 = arrayInfo >> 8; /* CC: index */ \
+ ILOGV("|aput%s v%d,v%d,v%d", (_opname), vdst, vsrc1, vsrc2); \
+ arrayObj = (ArrayObject*) GET_REGISTER(vsrc1); \
+ if (!checkForNull((Object*) arrayObj)) \
+ GOTO_exceptionThrown(); \
+ if (GET_REGISTER(vsrc2) >= arrayObj->length) { \
+ dvmThrowException("Ljava/lang/ArrayIndexOutOfBoundsException;", \
+ NULL); \
+ GOTO_exceptionThrown(); \
+ } \
+ ILOGV("+ APUT[%d]=0x%08x", GET_REGISTER(vsrc2), GET_REGISTER(vdst));\
+ ((_type*) arrayObj->contents)[GET_REGISTER(vsrc2)] = \
+ GET_REGISTER##_regsize(vdst); \
+ } \
+ FINISH(2);
+
+/*
+ * It's possible to get a bad value out of a field with sub-32-bit stores
+ * because the -quick versions always operate on 32 bits. Consider:
+ * short foo = -1 (sets a 32-bit register to 0xffffffff)
+ * iput-quick foo (writes all 32 bits to the field)
+ * short bar = 1 (sets a 32-bit register to 0x00000001)
+ * iput-short (writes the low 16 bits to the field)
+ * iget-quick foo (reads all 32 bits from the field, yielding 0xffff0001)
+ * This can only happen when optimized and non-optimized code has interleaved
+ * access to the same field. This is unlikely but possible.
+ *
+ * The easiest way to fix this is to always read/write 32 bits at a time. On
+ * a device with a 16-bit data bus this is sub-optimal. (The alternative
+ * approach is to have sub-int versions of iget-quick, but now we're wasting
+ * Dalvik instruction space and making it less likely that handler code will
+ * already be in the CPU i-cache.)
+ */
+#define HANDLE_IGET_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ InstField* ifield; \
+ Object* obj; \
+ EXPORT_PC(); \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|iget%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNull(obj)) \
+ GOTO_exceptionThrown(); \
+ ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
+ if (ifield == NULL) { \
+ ifield = dvmResolveInstField(curMethod->clazz, ref); \
+ if (ifield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, \
+ dvmGetField##_ftype(obj, ifield->byteOffset)); \
+ ILOGV("+ IGET '%s'=0x%08llx", ifield->field.name, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_GET(&ifield->field); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IGET_X_QUICK(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ Object* obj; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field offset */ \
+ ILOGV("|iget%s-quick v%d,v%d,field@+%u", \
+ (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNullExportPC(obj, fp, pc)) \
+ GOTO_exceptionThrown(); \
+ SET_REGISTER##_regsize(vdst, dvmGetField##_ftype(obj, ref)); \
+ ILOGV("+ IGETQ %d=0x%08llx", ref, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IPUT_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ InstField* ifield; \
+ Object* obj; \
+ EXPORT_PC(); \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|iput%s v%d,v%d,field@0x%04x", (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNull(obj)) \
+ GOTO_exceptionThrown(); \
+ ifield = (InstField*) dvmDexGetResolvedField(methodClassDex, ref); \
+ if (ifield == NULL) { \
+ ifield = dvmResolveInstField(curMethod->clazz, ref); \
+ if (ifield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ dvmSetField##_ftype(obj, ifield->byteOffset, \
+ GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ IPUT '%s'=0x%08llx", ifield->field.name, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_PUT(&ifield->field); \
+ } \
+ FINISH(2);
+
+#define HANDLE_IPUT_X_QUICK(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vA, vB, field@CCCC*/) \
+ { \
+ Object* obj; \
+ vdst = INST_A(inst); \
+ vsrc1 = INST_B(inst); /* object ptr */ \
+ ref = FETCH(1); /* field offset */ \
+ ILOGV("|iput%s-quick v%d,v%d,field@0x%04x", \
+ (_opname), vdst, vsrc1, ref); \
+ obj = (Object*) GET_REGISTER(vsrc1); \
+ if (!checkForNullExportPC(obj, fp, pc)) \
+ GOTO_exceptionThrown(); \
+ dvmSetField##_ftype(obj, ref, GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ IPUTQ %d=0x%08llx", ref, \
+ (u8) GET_REGISTER##_regsize(vdst)); \
+ } \
+ FINISH(2);
+
+#define HANDLE_SGET_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
+ { \
+ StaticField* sfield; \
+ vdst = INST_AA(inst); \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|sget%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
+ sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+ if (sfield == NULL) { \
+ EXPORT_PC(); \
+ sfield = dvmResolveStaticField(curMethod->clazz, ref); \
+ if (sfield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ SET_REGISTER##_regsize(vdst, dvmGetStaticField##_ftype(sfield)); \
+ ILOGV("+ SGET '%s'=0x%08llx", \
+ sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_GET(&sfield->field); \
+ } \
+ FINISH(2);
+
+#define HANDLE_SPUT_X(_opcode, _opname, _ftype, _regsize) \
+ HANDLE_OPCODE(_opcode /*vAA, field@BBBB*/) \
+ { \
+ StaticField* sfield; \
+ vdst = INST_AA(inst); \
+ ref = FETCH(1); /* field ref */ \
+ ILOGV("|sput%s v%d,sfield@0x%04x", (_opname), vdst, ref); \
+ sfield = (StaticField*)dvmDexGetResolvedField(methodClassDex, ref); \
+ if (sfield == NULL) { \
+ EXPORT_PC(); \
+ sfield = dvmResolveStaticField(curMethod->clazz, ref); \
+ if (sfield == NULL) \
+ GOTO_exceptionThrown(); \
+ } \
+ dvmSetStaticField##_ftype(sfield, GET_REGISTER##_regsize(vdst)); \
+ ILOGV("+ SPUT '%s'=0x%08llx", \
+ sfield->field.name, (u8)GET_REGISTER##_regsize(vdst)); \
+ UPDATE_FIELD_PUT(&sfield->field); \
+ } \
+ FINISH(2);
+
+
+/* File: cstubs/enddefs.c */
+
+/* undefine "magic" name remapping */
+#undef retval
+#undef pc
+#undef fp
+#undef curMethod
+#undef methodClassDex
+#undef self
+#undef debugTrackedRefStart
+
+/* File: armv5te/debug.c */
+#include <inttypes.h>
+
+/*
+ * Dump the fixed-purpose ARM registers, along with some other info.
+ *
+ * This function MUST be compiled in ARM mode -- THUMB will yield bogus
+ * results.
+ *
+ * This will NOT preserve r0-r3/ip.
+ */
+void dvmMterpDumpArmRegs(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3)
+{
+ register uint32_t rPC asm("r4");
+ register uint32_t rFP asm("r5");
+ register uint32_t rGLUE asm("r6");
+ register uint32_t rINST asm("r7");
+ register uint32_t rIBASE asm("r8");
+ register uint32_t r9 asm("r9");
+ register uint32_t r10 asm("r10");
+
+ 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;
+ printf(" + self is %p\n", dvmThreadSelf());
+ //printf(" + currently in %s.%s %s\n",
+ // method->clazz->descriptor, method->name, method->signature);
+ //printf(" + dvmAsmInstructionStart = %p\n", dvmAsmInstructionStart);
+ //printf(" + next handler for 0x%02x = %p\n",
+ // rINST & 0xff, dvmAsmInstructionStart + (rINST & 0xff) * 64);
+}
+
+/*
+ * Dump the StackSaveArea for the specified frame pointer.
+ */
+void dvmDumpFp(void* fp, StackSaveArea* otherSaveArea)
+{
+ StackSaveArea* saveArea = SAVEAREA_FROM_FP(fp);
+ printf("StackSaveArea for fp %p [%p/%p]:\n", fp, saveArea, otherSaveArea);
+#ifdef EASY_GDB
+ printf(" prevSave=%p, prevFrame=%p savedPc=%p meth=%p curPc=%p\n",
+ saveArea->prevSave, saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc);
+#else
+ printf(" prevFrame=%p savedPc=%p meth=%p curPc=%p fp[0]=0x%08x\n",
+ saveArea->prevFrame, saveArea->savedPc,
+ saveArea->method, saveArea->xtra.currentPc,
+ *(u4*)fp);
+#endif
+}
+
+/*
+ * Does the bulk of the work for common_printMethod().
+ */
+void dvmMterpPrintMethod(Method* method)
+{
+ /*
+ * It is a direct (non-virtual) method if it is static, private,
+ * or a constructor.
+ */
+ bool isDirect =
+ ((method->accessFlags & (ACC_STATIC|ACC_PRIVATE)) != 0) ||
+ (method->name[0] == '<');
+
+ char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
+
+ printf("<%c:%s.%s %s> ",
+ isDirect ? 'D' : 'V',
+ method->clazz->descriptor,
+ method->name,
+ desc);
+
+ free(desc);
+}
+
diff --git a/vm/mterp/out/InterpC-portdbg.c b/vm/mterp/out/InterpC-portdbg.c
index d527cc0..c8f428c 100644
--- a/vm/mterp/out/InterpC-portdbg.c
+++ b/vm/mterp/out/InterpC-portdbg.c
@@ -26,6 +26,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -53,7 +54,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -93,6 +94,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -116,9 +129,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -303,6 +320,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -316,29 +335,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -402,7 +413,6 @@
return true;
}
-
/* File: portable/portdbg.c */
#define INTERP_FUNC_NAME dvmInterpretDbg
#define INTERP_TYPE INTERP_DBG
@@ -410,6 +420,14 @@
#define CHECK_DEBUG_AND_PROF() \
checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
+#if defined(WITH_JIT)
+#define CHECK_JIT() \
+ if (dvmCheckJit(pc, self, interpState)) GOTO_bail_switch()
+#else
+#define CHECK_JIT() \
+ ((void)0)
+#endif
+
/* File: portable/stubdefs.c */
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -441,6 +459,7 @@
inst = FETCH(0); \
CHECK_DEBUG_AND_PROF(); \
CHECK_TRACKED_REFS(); \
+ CHECK_JIT(); \
goto *handlerTable[INST_INST(inst)]; \
}
#else
@@ -486,7 +505,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
interpState->entryPoint = _entryPoint; \
@@ -1458,11 +1480,32 @@
const Method* methodToCall;
bool methodCallRange;
+
#if defined(THREADED_INTERP)
/* static computed goto table */
DEFINE_GOTO_TABLE(handlerTable);
#endif
+#if defined(WITH_JIT)
+#if 0
+ LOGD("*DebugInterp - entrypoint is %d, tgt is 0x%x, %s\n",
+ interpState->entryPoint,
+ interpState->pc,
+ interpState->method->name);
+#endif
+
+#if INTERP_TYPE == INTERP_DBG
+ /* Check to see if we've got a trace selection request. If we do,
+ * but something is amiss, revert to the fast interpreter.
+ */
+ if (dvmJitCheckTraceRequest(self,interpState)) {
+ interpState->nextMode = INTERP_STD;
+ //LOGD("** something wrong, exiting\n");
+ return true;
+ }
+#endif
+#endif
+
/* copy state in */
curMethod = interpState->method;
pc = interpState->pc;
@@ -1869,9 +1912,7 @@
if (!checkForNullExportPC(obj, fp, pc))
GOTO_exceptionThrown();
ILOGV("+ locking %p %s\n", obj, obj->clazz->descriptor);
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC(); /* need for stack trace */
-#endif
+ EXPORT_PC(); /* need for precise GC, also WITH_MONITOR_TRACKING */
dvmLockObject(self, obj);
#ifdef WITH_DEADLOCK_PREDICTION
if (dvmCheckException(self))
@@ -2018,21 +2059,13 @@
GOTO_exceptionThrown();
/*
- * Note: the verifier can ensure that this never happens, allowing us
- * to remove the check. However, the spec requires we throw the
- * exception at runtime, not verify time, so the verifier would
- * need to replace the new-instance call with a magic "throw
- * InstantiationError" instruction.
- *
- * Since this relies on the verifier, which is optional, we would
- * also need a "new-instance-quick" instruction to identify instances
- * that don't require the check.
+ * Verifier now tests for interface/abstract class.
*/
- if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
- dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
- clazz->descriptor);
- GOTO_exceptionThrown();
- }
+ //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+ // dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
+ // clazz->descriptor);
+ // GOTO_exceptionThrown();
+ //}
newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
if (newObj == NULL)
GOTO_exceptionThrown();
@@ -3128,8 +3161,13 @@
HANDLE_OPCODE(OP_UNUSED_EC)
OP_END
-/* File: c/OP_UNUSED_ED.c */
-HANDLE_OPCODE(OP_UNUSED_ED)
+/* File: c/OP_THROW_VERIFICATION_ERROR.c */
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR)
+ EXPORT_PC();
+ vsrc1 = INST_AA(inst);
+ ref = FETCH(1); /* class/field/method ref */
+ dvmThrowVerificationError(curMethod, vsrc1, ref);
+ GOTO_exceptionThrown();
OP_END
/* File: c/OP_EXECUTE_INLINE.c */
@@ -4122,6 +4160,9 @@
#endif
newSaveArea->prevFrame = fp;
newSaveArea->savedPc = pc;
+#if defined(WITH_JIT)
+ newSaveArea->returnAddr = 0;
+#endif
newSaveArea->method = methodToCall;
if (!dvmIsNativeMethod(methodToCall)) {
@@ -4216,7 +4257,6 @@
assert(false); // should not get here
GOTO_TARGET_END
-
/* File: portable/enddefs.c */
/*--- end of opcodes ---*/
diff --git a/vm/mterp/out/InterpC-portstd.c b/vm/mterp/out/InterpC-portstd.c
index 64e5ccd..baf7a86 100644
--- a/vm/mterp/out/InterpC-portstd.c
+++ b/vm/mterp/out/InterpC-portstd.c
@@ -26,6 +26,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -53,7 +54,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -93,6 +94,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -116,9 +129,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -303,6 +320,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -316,29 +335,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -402,13 +413,14 @@
return true;
}
-
/* File: portable/portstd.c */
#define INTERP_FUNC_NAME dvmInterpretStd
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
+#define CHECK_JIT() ((void)0)
+
/* File: portable/stubdefs.c */
/*
* In the C mterp stubs, "goto" is a function call followed immediately
@@ -440,6 +452,7 @@
inst = FETCH(0); \
CHECK_DEBUG_AND_PROF(); \
CHECK_TRACKED_REFS(); \
+ CHECK_JIT(); \
goto *handlerTable[INST_INST(inst)]; \
}
#else
@@ -485,7 +498,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
interpState->entryPoint = _entryPoint; \
@@ -1178,11 +1194,32 @@
const Method* methodToCall;
bool methodCallRange;
+
#if defined(THREADED_INTERP)
/* static computed goto table */
DEFINE_GOTO_TABLE(handlerTable);
#endif
+#if defined(WITH_JIT)
+#if 0
+ LOGD("*DebugInterp - entrypoint is %d, tgt is 0x%x, %s\n",
+ interpState->entryPoint,
+ interpState->pc,
+ interpState->method->name);
+#endif
+
+#if INTERP_TYPE == INTERP_DBG
+ /* Check to see if we've got a trace selection request. If we do,
+ * but something is amiss, revert to the fast interpreter.
+ */
+ if (dvmJitCheckTraceRequest(self,interpState)) {
+ interpState->nextMode = INTERP_STD;
+ //LOGD("** something wrong, exiting\n");
+ return true;
+ }
+#endif
+#endif
+
/* copy state in */
curMethod = interpState->method;
pc = interpState->pc;
@@ -1589,9 +1626,7 @@
if (!checkForNullExportPC(obj, fp, pc))
GOTO_exceptionThrown();
ILOGV("+ locking %p %s\n", obj, obj->clazz->descriptor);
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC(); /* need for stack trace */
-#endif
+ EXPORT_PC(); /* need for precise GC, also WITH_MONITOR_TRACKING */
dvmLockObject(self, obj);
#ifdef WITH_DEADLOCK_PREDICTION
if (dvmCheckException(self))
@@ -1738,21 +1773,13 @@
GOTO_exceptionThrown();
/*
- * Note: the verifier can ensure that this never happens, allowing us
- * to remove the check. However, the spec requires we throw the
- * exception at runtime, not verify time, so the verifier would
- * need to replace the new-instance call with a magic "throw
- * InstantiationError" instruction.
- *
- * Since this relies on the verifier, which is optional, we would
- * also need a "new-instance-quick" instruction to identify instances
- * that don't require the check.
+ * Verifier now tests for interface/abstract class.
*/
- if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
- dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
- clazz->descriptor);
- GOTO_exceptionThrown();
- }
+ //if (dvmIsInterfaceClass(clazz) || dvmIsAbstractClass(clazz)) {
+ // dvmThrowExceptionWithClassMessage("Ljava/lang/InstantiationError;",
+ // clazz->descriptor);
+ // GOTO_exceptionThrown();
+ //}
newObj = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
if (newObj == NULL)
GOTO_exceptionThrown();
@@ -2848,8 +2875,13 @@
HANDLE_OPCODE(OP_UNUSED_EC)
OP_END
-/* File: c/OP_UNUSED_ED.c */
-HANDLE_OPCODE(OP_UNUSED_ED)
+/* File: c/OP_THROW_VERIFICATION_ERROR.c */
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR)
+ EXPORT_PC();
+ vsrc1 = INST_AA(inst);
+ ref = FETCH(1); /* class/field/method ref */
+ dvmThrowVerificationError(curMethod, vsrc1, ref);
+ GOTO_exceptionThrown();
OP_END
/* File: c/OP_EXECUTE_INLINE.c */
@@ -3842,6 +3874,9 @@
#endif
newSaveArea->prevFrame = fp;
newSaveArea->savedPc = pc;
+#if defined(WITH_JIT)
+ newSaveArea->returnAddr = 0;
+#endif
newSaveArea->method = methodToCall;
if (!dvmIsNativeMethod(methodToCall)) {
@@ -3936,7 +3971,6 @@
assert(false); // should not get here
GOTO_TARGET_END
-
/* File: portable/enddefs.c */
/*--- end of opcodes ---*/
diff --git a/vm/mterp/out/InterpC-x86.c b/vm/mterp/out/InterpC-x86.c
index cd5fe95..b17e530 100644
--- a/vm/mterp/out/InterpC-x86.c
+++ b/vm/mterp/out/InterpC-x86.c
@@ -26,6 +26,7 @@
#include "interp/InterpDefs.h"
#include "mterp/Mterp.h"
#include <math.h> // needed for fmod, fmodf
+#include "mterp/common/FindInterface.h"
/*
* Configuration defines. These affect the C implementations, i.e. the
@@ -53,7 +54,7 @@
*/
#define THREADED_INTERP /* threaded vs. while-loop interpreter */
-#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia */
+#ifdef WITH_INSTR_CHECKS /* instruction-level paranoia (slow!) */
# define CHECK_BRANCH_OFFSETS
# define CHECK_REGISTER_INDICES
#endif
@@ -93,6 +94,18 @@
#endif
/*
+ * Export another copy of the PC on every instruction; this is largely
+ * redundant with EXPORT_PC and the debugger code. This value can be
+ * compared against what we have stored on the stack with EXPORT_PC to
+ * help ensure that we aren't missing any export calls.
+ */
+#if WITH_EXTRA_GC_CHECKS > 1
+# define EXPORT_EXTRA_PC() (self->currentPc2 = pc)
+#else
+# define EXPORT_EXTRA_PC()
+#endif
+
+/*
* Adjust the program counter. "_offset" is a signed int, in 16-bit units.
*
* Assumes the existence of "const u2* pc" and "const u2* curMethod->insns".
@@ -116,9 +129,13 @@
dvmAbort(); \
} \
pc += myoff; \
+ EXPORT_EXTRA_PC(); \
} while (false)
#else
-# define ADJUST_PC(_offset) (pc += _offset)
+# define ADJUST_PC(_offset) do { \
+ pc += _offset; \
+ EXPORT_EXTRA_PC(); \
+ } while (false)
#endif
/*
@@ -303,6 +320,8 @@
* within the current method won't be shown correctly. See the notes
* in Exception.c.
*
+ * This is also used to determine the address for precise GC.
+ *
* Assumes existence of "u4* fp" and "const u2* pc".
*/
#define EXPORT_PC() (SAVEAREA_FROM_FP(fp)->xtra.currentPc = pc)
@@ -316,29 +335,21 @@
* If we're building without debug and profiling support, we never switch.
*/
#if defined(WITH_PROFILER) || defined(WITH_DEBUGGER)
+#if defined(WITH_JIT)
+# define NEED_INTERP_SWITCH(_current) ( \
+ (_current == INTERP_STD) ? \
+ dvmJitDebuggerOrProfilerActive(interpState->jitState) : \
+ !dvmJitDebuggerOrProfilerActive(interpState->jitState) )
+#else
# define NEED_INTERP_SWITCH(_current) ( \
(_current == INTERP_STD) ? \
dvmDebuggerOrProfilerActive() : !dvmDebuggerOrProfilerActive() )
+#endif
#else
# define NEED_INTERP_SWITCH(_current) (false)
#endif
/*
- * Look up an interface on a class using the cache.
- */
-INLINE Method* dvmFindInterfaceMethodInCache(ClassObject* thisClass,
- u4 methodIdx, const Method* method, DvmDex* methodClassDex)
-{
-#define ATOMIC_CACHE_CALC \
- dvmInterpFindInterfaceMethod(thisClass, methodIdx, method, methodClassDex)
-
- return (Method*) ATOMIC_CACHE_LOOKUP(methodClassDex->pInterfaceCache,
- DEX_INTERFACE_CACHE_SIZE, thisClass, methodIdx);
-
-#undef ATOMIC_CACHE_CALC
-}
-
-/*
* Check to see if "obj" is NULL. If so, throw an exception. Assumes the
* pc has already been exported to the stack.
*
@@ -402,7 +413,6 @@
return true;
}
-
/* File: cstubs/stubdefs.c */
/* this is a standard (no debug support) interpreter */
#define INTERP_TYPE INTERP_STD
@@ -513,7 +523,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
glue->entryPoint = _entryPoint; \
@@ -1172,6 +1185,15 @@
FINISH(2);
+/* File: c/OP_THROW_VERIFICATION_ERROR.c */
+HANDLE_OPCODE(OP_THROW_VERIFICATION_ERROR)
+ EXPORT_PC();
+ vsrc1 = INST_AA(inst);
+ ref = FETCH(1); /* class/field/method ref */
+ dvmThrowVerificationError(curMethod, vsrc1, ref);
+ GOTO_exceptionThrown();
+OP_END
+
/* File: c/gotoTargets.c */
/*
* C footer. This has some common code shared by the various targets.
@@ -2011,6 +2033,9 @@
#endif
newSaveArea->prevFrame = fp;
newSaveArea->savedPc = pc;
+#if defined(WITH_JIT)
+ newSaveArea->returnAddr = 0;
+#endif
newSaveArea->method = methodToCall;
if (!dvmIsNativeMethod(methodToCall)) {
@@ -2105,7 +2130,6 @@
assert(false); // should not get here
GOTO_TARGET_END
-
/* File: cstubs/enddefs.c */
/* undefine "magic" name remapping */
diff --git a/vm/mterp/portable/entry.c b/vm/mterp/portable/entry.c
index 6698959..9c7c2d6 100644
--- a/vm/mterp/portable/entry.c
+++ b/vm/mterp/portable/entry.c
@@ -29,11 +29,32 @@
const Method* methodToCall;
bool methodCallRange;
+
#if defined(THREADED_INTERP)
/* static computed goto table */
DEFINE_GOTO_TABLE(handlerTable);
#endif
+#if defined(WITH_JIT)
+#if 0
+ LOGD("*DebugInterp - entrypoint is %d, tgt is 0x%x, %s\n",
+ interpState->entryPoint,
+ interpState->pc,
+ interpState->method->name);
+#endif
+
+#if INTERP_TYPE == INTERP_DBG
+ /* Check to see if we've got a trace selection request. If we do,
+ * but something is amiss, revert to the fast interpreter.
+ */
+ if (dvmJitCheckTraceRequest(self,interpState)) {
+ interpState->nextMode = INTERP_STD;
+ //LOGD("** something wrong, exiting\n");
+ return true;
+ }
+#endif
+#endif
+
/* copy state in */
curMethod = interpState->method;
pc = interpState->pc;
diff --git a/vm/mterp/portable/portdbg.c b/vm/mterp/portable/portdbg.c
index a657f09..04132cb 100644
--- a/vm/mterp/portable/portdbg.c
+++ b/vm/mterp/portable/portdbg.c
@@ -3,3 +3,11 @@
#define CHECK_DEBUG_AND_PROF() \
checkDebugAndProf(pc, fp, self, curMethod, &debugIsMethodEntry)
+
+#if defined(WITH_JIT)
+#define CHECK_JIT() \
+ if (dvmCheckJit(pc, self, interpState)) GOTO_bail_switch()
+#else
+#define CHECK_JIT() \
+ ((void)0)
+#endif
diff --git a/vm/mterp/portable/portstd.c b/vm/mterp/portable/portstd.c
index 01fbda1..f55e8e7 100644
--- a/vm/mterp/portable/portstd.c
+++ b/vm/mterp/portable/portstd.c
@@ -2,3 +2,5 @@
#define INTERP_TYPE INTERP_STD
#define CHECK_DEBUG_AND_PROF() ((void)0)
+
+#define CHECK_JIT() ((void)0)
diff --git a/vm/mterp/portable/stubdefs.c b/vm/mterp/portable/stubdefs.c
index 0ea563c..305aebb 100644
--- a/vm/mterp/portable/stubdefs.c
+++ b/vm/mterp/portable/stubdefs.c
@@ -28,6 +28,7 @@
inst = FETCH(0); \
CHECK_DEBUG_AND_PROF(); \
CHECK_TRACKED_REFS(); \
+ CHECK_JIT(); \
goto *handlerTable[INST_INST(inst)]; \
}
#else
@@ -73,7 +74,10 @@
* started. If so, switch to a different "goto" table.
*/
#define PERIODIC_CHECKS(_entryPoint, _pcadj) { \
- dvmCheckSuspendQuick(self); \
+ if (dvmCheckSuspendQuick(self)) { \
+ EXPORT_PC(); /* need for precise GC */ \
+ dvmCheckSuspendPending(self); \
+ } \
if (NEED_INTERP_SWITCH(INTERP_TYPE)) { \
ADJUST_PC(_pcadj); \
interpState->entryPoint = _entryPoint; \
diff --git a/vm/mterp/rebuild.sh b/vm/mterp/rebuild.sh
index 1380f69..32c9007 100755
--- a/vm/mterp/rebuild.sh
+++ b/vm/mterp/rebuild.sh
@@ -19,7 +19,7 @@
# generated as part of the build.
#
set -e
-for arch in portstd portdbg allstubs armv4t armv5te x86; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
+for arch in portstd portdbg allstubs armv4t armv5te armv5te-vfp armv7-a x86; do TARGET_ARCH_EXT=$arch make -f Makefile-mterp; done
# These aren't actually used, so just go ahead and remove them. The correct
# approach is to prevent them from being generated in the first place, but
diff --git a/vm/mterp/x86/OP_INVOKE_DIRECT.S b/vm/mterp/x86/OP_INVOKE_DIRECT.S
index a772540..f423dc3 100644
--- a/vm/mterp/x86/OP_INVOKE_DIRECT.S
+++ b/vm/mterp/x86/OP_INVOKE_DIRECT.S
@@ -30,9 +30,7 @@
.L${opcode}_finish:
UNSPILL(rPC)
testl %ecx,%ecx # null "this"?
- movl $$$isrange,%ecx
- #jne common_invokeMethod${routine} # no, continue on
- jne common_invokeOld # no, continue on, eax<- method, ecx<- methodCallRange
+ jne common_invokeMethod${routine} # no, continue on
jmp common_errNullObject
%break
diff --git a/vm/mterp/x86/OP_INVOKE_INTERFACE.S b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
index 02dc76f..1631177 100644
--- a/vm/mterp/x86/OP_INVOKE_INTERFACE.S
+++ b/vm/mterp/x86/OP_INVOKE_INTERFACE.S
@@ -35,7 +35,5 @@
UNSPILL(rPC)
testl %eax,%eax
je common_exceptionThrown
- movl $$$isrange,%ecx
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_STATIC.S b/vm/mterp/x86/OP_INVOKE_STATIC.S
index c65fc1f..40dac06 100644
--- a/vm/mterp/x86/OP_INVOKE_STATIC.S
+++ b/vm/mterp/x86/OP_INVOKE_STATIC.S
@@ -14,10 +14,8 @@
EXPORT_PC()
movl offDvmDex_pResMethods(%ecx),%ecx # ecx<- pDvmDex->pResMethods
movl (%ecx,%eax,4),%eax # eax<- resolved methodToCall
- movl $$$isrange,%ecx # needed by common_invokeOld - revisit
testl %eax,%eax
- #jne common_invokeMethod${routine}
- jne common_invokeOld
+ jne common_invokeMethod${routine}
GET_GLUE(%ecx)
movl offGlue_method(%ecx),%ecx # ecx<- glue->method
movzwl 2(rPC),%eax
@@ -33,9 +31,7 @@
SPILL(rPC)
call dvmResolveMethod # call(clazz,ref,flags)
UNSPILL(rPC)
- movl $$$isrange,%ecx
testl %eax,%eax # got null?
- #jne common_invokeMethod${routine}
- jne common_invokeOld
+ jne common_invokeMethod${routine}
jmp common_exceptionThrown
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER.S b/vm/mterp/x86/OP_INVOKE_SUPER.S
index d0a6ad6..013fc01 100644
--- a/vm/mterp/x86/OP_INVOKE_SUPER.S
+++ b/vm/mterp/x86/OP_INVOKE_SUPER.S
@@ -40,9 +40,8 @@
jae .L${opcode}_nsm # method not present in superclass
movl offClassObject_vtable(%eax),%eax # eax<- ...clazz->super->vtable
movl (%eax,%ecx,4),%eax # eax<- vtable[methodIndex]
- movl $$$isrange,%ecx
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
+
/* At this point:
* ecx = null (needs to be resolved base method)
diff --git a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
index b050c82..7545eb0 100644
--- a/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
+++ b/vm/mterp/x86/OP_INVOKE_SUPER_QUICK.S
@@ -23,7 +23,5 @@
movl offClassObject_vtable(%ecx),%ecx # ecx<- vtable
EXPORT_PC()
movl (%ecx,%eax,4),%eax # eax<- super->vtable[BBBB]
- movl $$$isrange,%ecx # ecx<- range flag
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
diff --git a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
index 6d32a81..20d9120 100644
--- a/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL.S
@@ -52,7 +52,5 @@
movl offObject_clazz(%ecx),%ecx # ecx<- thisPtr->clazz
movl offClassObject_vtable(%ecx),%ecx # ecx<- thisPtr->clazz->vtable
movl (%ecx,%eax,4),%eax # eax<- vtable[methodIndex]
- movl $$$isrange,%ecx # needed for common_invokeOld
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ 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 d197f29..f36ed2d 100644
--- a/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
+++ b/vm/mterp/x86/OP_INVOKE_VIRTUAL_QUICK.S
@@ -20,7 +20,6 @@
movl offClassObject_vtable(%eax),%eax # eax<- thisPtr->clazz->vtable
EXPORT_PC() # might throw later - get ready
movl (%eax,%ecx,4),%eax # eax<- vtable[BBBB]
- movl $$$isrange,%ecx # pass range flag
- #jmp common_invokeMethod${routine}
- jmp common_invokeOld
+ jmp common_invokeMethod${routine}
+
diff --git a/vm/mterp/x86/OP_MONITOR_ENTER.S b/vm/mterp/x86/OP_MONITOR_ENTER.S
index 18425f4..548f71f 100644
--- a/vm/mterp/x86/OP_MONITOR_ENTER.S
+++ b/vm/mterp/x86/OP_MONITOR_ENTER.S
@@ -10,9 +10,7 @@
movl offGlue_self(%ecx),%ecx # ecx<- glue->self
FETCH_INST_WORD(1)
testl %eax,%eax # null object?
-#ifdef WITH_MONITOR_TRACKING
- EXPORT_PC()
-#endif
+ EXPORT_PC() # need for precise GC, MONITOR_TRACKING
jne .L${opcode}_continue
jmp common_errNullObject
%break
diff --git a/vm/mterp/x86/OP_NEW_INSTANCE.S b/vm/mterp/x86/OP_NEW_INSTANCE.S
index da951f7..d56d55c 100644
--- a/vm/mterp/x86/OP_NEW_INSTANCE.S
+++ b/vm/mterp/x86/OP_NEW_INSTANCE.S
@@ -27,6 +27,7 @@
%break
.L${opcode}_initialized: # on entry, ecx<- class
+ /* TODO: remove test for interface/abstract, now done in verifier */
testl $$(ACC_INTERFACE|ACC_ABSTRACT),offClassObject_accessFlags(%ecx)
movl $$ALLOC_DONT_TRACK,OUT_ARG1(%esp)
jne .L${opcode}_abstract
@@ -77,6 +78,7 @@
jmp common_exceptionThrown # no, handle exception
/*
+ * TODO: remove this
* We can't instantiate an abstract class or interface, so throw an
* InstantiationError with the class descriptor as the message.
*
diff --git a/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S
new file mode 100644
index 0000000..d59eb1a
--- /dev/null
+++ b/vm/mterp/x86/OP_THROW_VERIFICATION_ERROR.S
@@ -0,0 +1,4 @@
+%verify executed
+ /* TODO */
+ call dvmAbort
+
diff --git a/vm/mterp/x86/OP_UNUSED_ED.S b/vm/mterp/x86/OP_UNUSED_ED.S
deleted file mode 100644
index 31d98c1..0000000
--- a/vm/mterp/x86/OP_UNUSED_ED.S
+++ /dev/null
@@ -1 +0,0 @@
-%include "x86/unused.S"
diff --git a/vm/mterp/x86/footer.S b/vm/mterp/x86/footer.S
index 50634dd..d86207a 100644
--- a/vm/mterp/x86/footer.S
+++ b/vm/mterp/x86/footer.S
@@ -25,11 +25,217 @@
*/
common_backwardBranch:
GET_GLUE(%ecx)
- call common_periodicChecks # Note: expects rPC to be preserved
+ call common_periodicChecks # Note: expects rPC to be preserved
ADVANCE_PC_INDEXED(rINST_FULL)
FETCH_INST()
GOTO_NEXT
+
+
+/*
+ * Common code for method invocation with range.
+ *
+ * On entry:
+ * eax = Method* methodToCall
+ * rINST trashed, must reload
+ */
+
+common_invokeMethodRange:
+.LinvokeNewRange:
+
+ /*
+ * prepare to copy args to "outs" area of current frame
+ */
+
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- AA
+ movzwl 4(rPC), %ecx # %ecx<- CCCC
+ SPILL(rPC)
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+ test rINST_FULL, rINST_FULL
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- AA
+ jz .LinvokeArgsDone # no args; jump to args done
+
+
+ /*
+ * %eax=methodToCall, %ecx=CCCC, LOCAL0_OFFSET(%ebp)=count, %edx=&outs (&stackSaveArea)
+ * (very few methods have > 10 args; could unroll for common cases)
+ */
+
+ movl %ebx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- save %ebx
+ lea (rFP, %ecx, 4), %ecx # %ecx<- &vCCCC
+ shll $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+ subl LOCAL0_OFFSET(%ebp), %edx # %edx<- update &outs
+ shrl $$2, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- offset
+1:
+ movl (%ecx), %ebx # %ebx<- vCCCC
+ lea 4(%ecx), %ecx # %ecx<- &vCCCC++
+ subl $$1, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- LOCAL0_OFFSET--
+ movl %ebx, (%edx) # *outs<- vCCCC
+ lea 4(%edx), %edx # outs++
+ jne 1b # loop if count (LOCAL0_OFFSET(%ebp)) not zero
+ movl LOCAL1_OFFSET(%ebp), %ebx # %ebx<- restore %ebx
+ jmp .LinvokeArgsDone # continue
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * prepare to copy args to "outs" area of current frame
+ */
+
+common_invokeMethodNoRange:
+.LinvokeNewNoRange:
+ movzbl 1(rPC),rINST_FULL # rINST_FULL<- BA
+ SPILL(rPC)
+ movl rINST_FULL, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- BA
+ shrl $$4, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET(%ebp)<- B
+ je .LinvokeArgsDone # no args; jump to args done
+ movzwl 4(rPC), %ecx # %ecx<- GFED
+ SAVEAREA_FROM_FP(%edx,rFP) # %edx<- &StackSaveArea
+
+ /*
+ * %eax=methodToCall, %ecx=GFED, LOCAL0_OFFSET(%ebp)=count, %edx=outs
+ */
+
+.LinvokeNonRange:
+ cmp $$2, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 2
+ movl %ecx, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- GFED
+ jl 1f # handle 1 arg
+ je 2f # handle 2 args
+ cmp $$4, LOCAL0_OFFSET(%ebp) # compare LOCAL0_OFFSET(%ebp) to 4
+ jl 3f # handle 3 args
+ je 4f # handle 4 args
+5:
+ andl $$15, rINST_FULL # rINST<- A
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, rINST_FULL, 4), %ecx # %ecx<- vA
+ movl %ecx, (%edx) # *outs<- vA
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+4:
+ shr $$12, %ecx # %ecx<- G
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vG
+ movl %ecx, (%edx) # *outs<- vG
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+3:
+ and $$0x0f00, %ecx # %ecx<- 0F00
+ shr $$8, %ecx # %ecx<- F
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vF
+ movl %ecx, (%edx) # *outs<- vF
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+2:
+ and $$0x00f0, %ecx # %ecx<- 00E0
+ shr $$4, %ecx # %ecx<- E
+ lea -4(%edx), %edx # %edx<- update &outs; &outs--
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vE
+ movl %ecx, (%edx) # *outs<- vE
+ movl LOCAL1_OFFSET(%ebp), %ecx # %ecx<- GFED
+1:
+ and $$0x000f, %ecx # %ecx<- 000D
+ movl (rFP, %ecx, 4), %ecx # %ecx<- vD
+ movl %ecx, -4(%edx) # *--outs<- vD
+0:
+
+ /*
+ * %eax is "Method* methodToCall", the method we're trying to call
+ * find space for the new stack frame, check for overflow
+ */
+
+.LinvokeArgsDone:
+ movzwl offMethod_registersSize(%eax), %edx # %edx<- methodToCall->regsSize
+ movzwl offMethod_outsSize(%eax), %ecx # %ecx<- methodToCall->outsSize
+ movl %eax, LOCAL0_OFFSET(%ebp) # LOCAL0_OFFSET<- methodToCall
+ shl $$2, %edx # %edx<- update offset
+ SAVEAREA_FROM_FP(%eax,rFP) # %eax<- &StackSaveArea
+ subl %edx, %eax # %eax<- newFP; (old savearea - regsSize)
+ GET_GLUE(%edx) # %edx<- pMterpGlue
+ movl %eax, LOCAL1_OFFSET(%ebp) # LOCAL1_OFFSET(%ebp)<- &outs
+ subl $$sizeofStackSaveArea, %eax # %eax<- newSaveArea (stack save area using newFP)
+ movl offGlue_interpStackEnd(%edx), %edx # %edx<- glue->interpStackEnd
+ movl %edx, LOCAL2_OFFSET(%ebp) # LOCAL2_OFFSET<- glue->interpStackEnd
+ shl $$2, %ecx # %ecx<- update offset for outsSize
+ movl %eax, %edx # %edx<- newSaveArea
+ sub %ecx, %eax # %eax<- bottom; (newSaveArea - outsSize)
+ cmp LOCAL2_OFFSET(%ebp), %eax # compare interpStackEnd and bottom
+ movl LOCAL0_OFFSET(%ebp), %eax # %eax<- restore methodToCall
+ jl .LstackOverflow # handle frame overflow
+
+ /*
+ * set up newSaveArea
+ */
+
+#ifdef EASY_GDB
+ SAVEAREA_FROM_FP(%ecx,rFP) # %ecx<- &StackSaveArea
+ movl %ecx, offStackSaveArea_prevSave(%edx) # newSaveArea->prevSave<- &outs
+#endif
+ movl rFP, offStackSaveArea_prevFrame(%edx) # newSaveArea->prevFrame<- rFP
+ movl rPC_SPILL(%ebp), %ecx
+ movl %ecx, offStackSaveArea_savedPc(%edx) # newSaveArea->savedPc<- rPC
+ testl $$ACC_NATIVE, offMethod_accessFlags(%eax) # check for native call
+ movl %eax, offStackSaveArea_method(%edx) # newSaveArea->method<- method to call
+ jne .LinvokeNative # handle native call
+
+ /*
+ * Update "glue" values for the new method
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFp
+ */
+
+ movl offMethod_clazz(%eax), %edx # %edx<- method->clazz
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl offClassObject_pDvmDex(%edx), %edx # %edx<- method->clazz->pDvmDex
+ movl %eax, offGlue_method(%ecx) # glue->method<- methodToCall
+ movl %edx, offGlue_methodClassDex(%ecx) # glue->methodClassDex<- method->clazz->pDvmDex
+ movl offMethod_insns(%eax), rPC # rPC<- methodToCall->insns
+ movl offGlue_self(%ecx), %eax # %eax<- glue->self
+ movl LOCAL1_OFFSET(%ebp), rFP # rFP<- newFP
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- newFP
+ FETCH_INST()
+ GOTO_NEXT # jump to methodToCall->insns
+
+ /*
+ * Prep for the native call
+ * %eax=methodToCall, LOCAL1_OFFSET(%ebp)=newFP, %edx=newSaveArea
+ */
+
+.LinvokeNative:
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl %eax, OUT_ARG1(%esp) # push parameter methodToCall
+ movl offGlue_self(%ecx), %ecx # %ecx<- glue->self
+ movl offThread_jniLocal_nextEntry(%ecx), %eax # %eax<- glue->self->thread->refNext
+ movl %eax, offStackSaveArea_localRefTop(%edx) # newSaveArea->localRefTop<- refNext
+ movl %edx, OUT_ARG4(%esp) # save newSaveArea
+ movl LOCAL1_OFFSET(%ebp), %edx # %edx<- newFP
+ movl %edx, offThread_curFrame(%ecx) # glue->self->curFrame<- newFP
+ movl %ecx, OUT_ARG3(%esp) # save glue->self
+ movl %ecx, OUT_ARG2(%esp) # push parameter glue->self
+ GET_GLUE(%ecx) # %ecx<- pMterpGlue
+ movl OUT_ARG1(%esp), %eax # %eax<- methodToCall
+ lea offGlue_retval(%ecx), %ecx # %ecx<- &retval
+ movl %ecx, OUT_ARG0(%esp) # push parameter pMterpGlue
+ push %edx # push parameter newFP
+
+ call *offMethod_nativeFunc(%eax) # call methodToCall->nativeFunc
+ lea 4(%esp), %esp
+ movl OUT_ARG4(%esp), %ecx # %ecx<- newSaveArea
+ movl OUT_ARG3(%esp), %eax # %eax<- glue->self
+ movl offStackSaveArea_localRefTop(%ecx), %edx # %edx<- newSaveArea->localRefTop
+ cmp $$0, offThread_exception(%eax) # check for exception
+ movl rFP, offThread_curFrame(%eax) # glue->self->curFrame<- rFP
+ movl %edx, offThread_jniLocal_nextEntry(%eax) # glue->self<- newSaveArea->localRefTop
+ UNSPILL(rPC)
+ jne common_exceptionThrown # handle exception
+ FETCH_INST_WORD(3)
+ ADVANCE_PC(3)
+ GOTO_NEXT # jump to next instruction
+
+.LstackOverflow:
+ GET_GLUE(%eax) # %eax<- pMterpGlue
+ movl offGlue_self(%eax), %eax # %eax<- glue->self
+ movl %eax, OUT_ARG0(%esp) # push parameter self
+ call dvmHandleStackOverflow # call: (Thread* self)
+ UNSPILL(rPC) # return: void
+ jmp common_exceptionThrown # handle exception
+
+
/*
* Common invoke code (old-style).
* TUNING: Rewrite along lines of new armv5 code?
@@ -106,6 +312,7 @@
* bool dvmCheckSuspendPending(Thread* self)
* Because we reached here via a call, go ahead and build a new frame.
*/
+ EXPORT_PC() # need for precise GC
movl offGlue_self(%ecx),%eax # eax<- glue->self
SPILL(rPC) # save edx
push %ebp
diff --git a/vm/native/dalvik_system_VMDebug.c b/vm/native/dalvik_system_VMDebug.c
index bf7ce61..d0fb61d 100644
--- a/vm/native/dalvik_system_VMDebug.c
+++ b/vm/native/dalvik_system_VMDebug.c
@@ -586,6 +586,118 @@
RETURN_VOID();
}
+/*
+ * static boolean cacheRegisterMap(String classAndMethodDescr)
+ *
+ * If the specified class is loaded, and the named method exists, ensure
+ * that the method's register map is ready for use. If the class/method
+ * cannot be found, nothing happens.
+ *
+ * This can improve the zygote's sharing of compressed register maps. Do
+ * this after class preloading.
+ *
+ * Returns true if the register map is cached and ready, either as a result
+ * of this call or earlier activity. Returns false if the class isn't loaded,
+ * if the method couldn't be found, or if the method has no register map.
+ *
+ * (Uncomment logs in dvmGetExpandedRegisterMap0() to gather stats.)
+ */
+static void Dalvik_dalvik_system_VMDebug_cacheRegisterMap(const u4* args,
+ JValue* pResult)
+{
+ StringObject* classAndMethodDescStr = (StringObject*) args[0];
+ ClassObject* clazz;
+ bool result = false;
+
+ if (classAndMethodDescStr == NULL) {
+ dvmThrowException("Ljava/lang/NullPointerException;", NULL);
+ RETURN_VOID();
+ }
+
+ char* classAndMethodDesc = NULL;
+
+ /*
+ * Pick the string apart. We have a local copy, so just modify it
+ * in place.
+ */
+ classAndMethodDesc = dvmCreateCstrFromString(classAndMethodDescStr);
+
+ char* methodName = strchr(classAndMethodDesc, '.');
+ if (methodName == NULL) {
+ dvmThrowException("Ljava/lang/RuntimeException;",
+ "method name not found in string");
+ RETURN_VOID();
+ }
+ *methodName++ = '\0';
+
+ char* methodDescr = strchr(methodName, ':');
+ if (methodDescr == NULL) {
+ dvmThrowException("Ljava/lang/RuntimeException;",
+ "method descriptor not found in string");
+ RETURN_VOID();
+ }
+ *methodDescr++ = '\0';
+
+ //LOGD("GOT: %s %s %s\n", classAndMethodDesc, methodName, methodDescr);
+
+ /*
+ * Find the class, but only if it's already loaded.
+ */
+ clazz = dvmLookupClass(classAndMethodDesc, NULL, false);
+ if (clazz == NULL) {
+ LOGD("Class %s not found in bootstrap loader\n", classAndMethodDesc);
+ goto bail;
+ }
+
+ Method* method;
+
+ /*
+ * Find the method, which could be virtual or direct, defined directly
+ * or inherited.
+ */
+ if (methodName[0] == '<') {
+ /*
+ * Constructor or class initializer. Only need to examine the
+ * "direct" list, and don't need to search up the class hierarchy.
+ */
+ method = dvmFindDirectMethodByDescriptor(clazz, methodName,
+ methodDescr);
+ } else {
+ /*
+ * Try both lists, and scan up the tree.
+ */
+ method = dvmFindVirtualMethodHierByDescriptor(clazz, methodName,
+ methodDescr);
+ if (method == NULL) {
+ method = dvmFindDirectMethodHierByDescriptor(clazz, methodName,
+ methodDescr);
+ }
+ }
+
+ if (method != NULL) {
+ /*
+ * Got it. See if there's a register map here.
+ */
+ const RegisterMap* pMap;
+ pMap = dvmGetExpandedRegisterMap(method);
+ if (pMap == NULL) {
+ LOGV("No map for %s.%s %s\n",
+ classAndMethodDesc, methodName, methodDescr);
+ } else {
+ LOGV("Found map %s.%s %s\n",
+ classAndMethodDesc, methodName, methodDescr);
+ result = true;
+ }
+ } else {
+ LOGV("Unable to find %s.%s %s\n",
+ classAndMethodDesc, methodName, methodDescr);
+ }
+
+bail:
+ free(classAndMethodDesc);
+ RETURN_BOOLEAN(result);
+}
+
const DalvikNativeMethod dvm_dalvik_system_VMDebug[] = {
{ "getAllocCount", "(I)I",
Dalvik_dalvik_system_VMDebug_getAllocCount },
@@ -633,6 +745,8 @@
Dalvik_dalvik_system_VMDebug_threadCpuTimeNanos },
{ "dumpHprofData", "(Ljava/lang/String;)V",
Dalvik_dalvik_system_VMDebug_dumpHprofData },
+ { "cacheRegisterMap", "(Ljava/lang/String;)Z",
+ Dalvik_dalvik_system_VMDebug_cacheRegisterMap },
{ NULL, NULL, NULL },
};
diff --git a/vm/oo/Class.c b/vm/oo/Class.c
index 00f5683..999a1a1 100644
--- a/vm/oo/Class.c
+++ b/vm/oo/Class.c
@@ -478,7 +478,7 @@
cc = stat(cpe->fileName, &sb);
if (cc < 0) {
- LOGW("Unable to stat classpath element '%s'\n", cpe->fileName);
+ LOGD("Unable to stat classpath element '%s'\n", cpe->fileName);
return false;
}
if (S_ISDIR(sb.st_mode)) {
@@ -510,6 +510,7 @@
return true;
}
+ LOGD("Unable to process classpath element '%s'\n", cpe->fileName);
return false;
}
@@ -517,13 +518,13 @@
* Convert a colon-separated list of directories, Zip files, and DEX files
* into an array of ClassPathEntry structs.
*
- * If we're unable to load a bootstrap class path entry, we fail. This
- * is necessary to preserve the dependencies implied by optimized DEX files
- * (e.g. if the same class appears in multiple places).
- *
* During normal startup we fail if there are no entries, because we won't
* get very far without the basic language support classes, but if we're
* optimizing a DEX file we allow it.
+ *
+ * If entries are added or removed from the bootstrap class path, the
+ * dependencies in the DEX files will break, and everything except the
+ * very first entry will need to be regenerated.
*/
static ClassPathEntry* processClassPath(const char* pathStr, bool isBootstrap)
{
@@ -583,16 +584,8 @@
cpe[idx].ptr = NULL;
if (!prepareCpe(&tmp, isBootstrap)) {
- LOGD("Failed on '%s' (boot=%d)\n", tmp.fileName, isBootstrap);
/* drop from list and continue on */
free(tmp.fileName);
-
- if (isBootstrap || gDvm.optimizing) {
- /* if boot path entry or we're optimizing, this is fatal */
- free(cpe);
- cpe = NULL;
- goto bail;
- }
} else {
/* copy over, pointers and all */
if (tmp.fileName[0] != '/')
@@ -1760,7 +1753,39 @@
dvmLinearReadOnly(classLoader, newClass->ifields);
}
- /* load method definitions */
+ /*
+ * Load method definitions. We do this in two batches, direct then
+ * virtual.
+ *
+ * If register maps have already been generated for this class, and
+ * precise GC is enabled, we pull out pointers to them. We know that
+ * they were streamed to the DEX file in the same order in which the
+ * methods appear.
+ *
+ * If the class wasn't pre-verified, the maps will be generated when
+ * the class is verified during class initialization.
+ */
+ u4 classDefIdx = dexGetIndexForClassDef(pDexFile, pClassDef);
+ const void* classMapData;
+ u4 numMethods;
+
+ if (gDvm.preciseGc) {
+ classMapData =
+ dvmRegisterMapGetClassData(pDexFile, classDefIdx, &numMethods);
+
+ /* sanity check */
+ if (classMapData != NULL &&
+ pHeader->directMethodsSize + pHeader->virtualMethodsSize != numMethods)
+ {
+ LOGE("ERROR: in %s, direct=%d virtual=%d, maps have %d\n",
+ newClass->descriptor, pHeader->directMethodsSize,
+ pHeader->virtualMethodsSize, numMethods);
+ assert(false);
+ classMapData = NULL; /* abandon */
+ }
+ } else {
+ classMapData = NULL;
+ }
if (pHeader->directMethodsSize != 0) {
int count = (int) pHeader->directMethodsSize;
@@ -1773,6 +1798,15 @@
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->directMethods[i]);
+ if (classMapData != NULL) {
+ const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
+ if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
+ newClass->directMethods[i].registerMap = pMap;
+ /* TODO: add rigorous checks */
+ assert((newClass->directMethods[i].registersSize+7) / 8 ==
+ newClass->directMethods[i].registerMap->regWidth);
+ }
+ }
}
dvmLinearReadOnly(classLoader, newClass->directMethods);
}
@@ -1788,6 +1822,15 @@
for (i = 0; i < count; i++) {
dexReadClassDataMethod(&pEncodedData, &method, &lastIndex);
loadMethodFromDex(newClass, &method, &newClass->virtualMethods[i]);
+ if (classMapData != NULL) {
+ const RegisterMap* pMap = dvmRegisterMapGetNext(&classMapData);
+ if (dvmRegisterMapGetFormat(pMap) != kRegMapFormatNone) {
+ newClass->virtualMethods[i].registerMap = pMap;
+ /* TODO: add rigorous checks */
+ assert((newClass->virtualMethods[i].registersSize+7) / 8 ==
+ newClass->virtualMethods[i].registerMap->regWidth);
+ }
+ }
}
dvmLinearReadOnly(classLoader, newClass->virtualMethods);
}
@@ -1912,9 +1955,11 @@
int directMethodCount = clazz->directMethodCount;
clazz->directMethods = NULL;
clazz->directMethodCount = -1;
+ dvmLinearReadWrite(clazz->classLoader, directMethods);
for (i = 0; i < directMethodCount; i++) {
freeMethodInnards(&directMethods[i]);
}
+ dvmLinearReadOnly(clazz->classLoader, directMethods);
dvmLinearFree(clazz->classLoader, directMethods);
}
if (clazz->virtualMethods != NULL) {
@@ -1922,9 +1967,11 @@
int virtualMethodCount = clazz->virtualMethodCount;
clazz->virtualMethodCount = -1;
clazz->virtualMethods = NULL;
+ dvmLinearReadWrite(clazz->classLoader, virtualMethods);
for (i = 0; i < virtualMethodCount; i++) {
freeMethodInnards(&virtualMethods[i]);
}
+ dvmLinearReadOnly(clazz->classLoader, virtualMethods);
dvmLinearFree(clazz->classLoader, virtualMethods);
}
@@ -1953,6 +2000,8 @@
/*
* Free anything in a Method that was allocated on the system heap.
+ *
+ * The containing class is largely torn down by this point.
*/
static void freeMethodInnards(Method* meth)
{
@@ -1960,26 +2009,39 @@
free(meth->exceptions);
free(meth->lines);
free(meth->locals);
-#else
- // TODO: call dvmFreeRegisterMap() if meth->registerMap was allocated
- // on the system heap
- UNUSED_PARAMETER(meth);
#endif
+
+ /*
+ * Some register maps are allocated on the heap, either because of late
+ * verification or because we're caching an uncompressed form.
+ */
+ const RegisterMap* pMap = meth->registerMap;
+ if (pMap != NULL && dvmRegisterMapGetOnHeap(pMap)) {
+ dvmFreeRegisterMap((RegisterMap*) pMap);
+ meth->registerMap = NULL;
+ }
+
+ /*
+ * We may have copied the instructions.
+ */
+ if (IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
+ DexCode* methodDexCode = (DexCode*) dvmGetMethodCode(meth);
+ dvmLinearFree(meth->clazz->classLoader, methodDexCode);
+ }
}
/*
* Clone a Method, making new copies of anything that will be freed up
- * by freeMethodInnards().
+ * by freeMethodInnards(). This is used for "miranda" methods.
*/
static void cloneMethod(Method* dst, const Method* src)
{
+ if (src->registerMap != NULL) {
+ LOGE("GLITCH: only expected abstract methods here\n");
+ LOGE(" cloning %s.%s\n", src->clazz->descriptor, src->name);
+ dvmAbort();
+ }
memcpy(dst, src, sizeof(Method));
-#if 0
- /* for current usage, these are never set, so no need to implement copy */
- assert(dst->exceptions == NULL);
- assert(dst->lines == NULL);
- assert(dst->locals == NULL);
-#endif
}
/*
@@ -2042,6 +2104,55 @@
}
/*
+ * We usually map bytecode directly out of the DEX file, which is mapped
+ * shared read-only. If we want to be able to modify it, we have to make
+ * a new copy.
+ *
+ * Once copied, the code will be in the LinearAlloc region, which may be
+ * marked read-only.
+ *
+ * The bytecode instructions are embedded inside a DexCode structure, so we
+ * need to copy all of that. (The dvmGetMethodCode function backs up the
+ * instruction pointer to find the start of the DexCode.)
+ */
+void dvmMakeCodeReadWrite(Method* meth)
+{
+ DexCode* methodDexCode = (DexCode*) dvmGetMethodCode(meth);
+
+ if (IS_METHOD_FLAG_SET(meth, METHOD_ISWRITABLE)) {
+ dvmLinearReadWrite(meth->clazz->classLoader, methodDexCode);
+ return;
+ }
+
+ assert(!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth));
+
+ size_t dexCodeSize = dexGetDexCodeSize(methodDexCode);
+ LOGD("Making a copy of %s.%s code (%d bytes)\n",
+ meth->clazz->descriptor, meth->name, dexCodeSize);
+
+ DexCode* newCode =
+ (DexCode*) dvmLinearAlloc(meth->clazz->classLoader, dexCodeSize);
+ memcpy(newCode, methodDexCode, dexCodeSize);
+
+ meth->insns = newCode->insns;
+ SET_METHOD_FLAG(meth, METHOD_ISWRITABLE);
+}
+
+/*
+ * Mark the bytecode read-only.
+ *
+ * If the contents of the DexCode haven't actually changed, we could revert
+ * to the original shared page.
+ */
+void dvmMakeCodeReadOnly(Method* meth)
+{
+ DexCode* methodDexCode = (DexCode*) dvmGetMethodCode(meth);
+ LOGV("+++ marking %p read-only\n", methodDexCode);
+ dvmLinearReadOnly(meth->clazz->classLoader, methodDexCode);
+}
+
+
+/*
* jniArgInfo (32-bit int) layout:
* SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
*
@@ -3116,6 +3227,7 @@
}
if (mirandaCount != 0) {
+ static const int kManyMirandas = 150; /* arbitrary */
Method* newVirtualMethods;
Method* meth;
int oldMethodCount, oldVtableCount;
@@ -3124,6 +3236,17 @@
LOGVV("MIRANDA %d: %s.%s\n", i,
mirandaList[i]->clazz->descriptor, mirandaList[i]->name);
}
+ if (mirandaCount > kManyMirandas) {
+ /*
+ * Some obfuscators like to create an interface with a huge
+ * pile of methods, declare classes as implementing it, and then
+ * only define a couple of methods. This leads to a rather
+ * massive collection of Miranda methods and a lot of wasted
+ * space, sometimes enough to blow out the LinearAlloc cap.
+ */
+ LOGD("Note: class %s has %d unimplemented (abstract) methods\n",
+ clazz->descriptor, mirandaCount);
+ }
/*
* We found methods in one or more interfaces for which we do not
@@ -3190,6 +3313,9 @@
* Now we need to create the fake methods. We clone the abstract
* method definition from the interface and then replace a few
* things.
+ *
+ * The Method will be an "abstract native", with nativeFunc set to
+ * dvmAbstractMethodStub().
*/
meth = clazz->virtualMethods + oldMethodCount;
for (i = 0; i < mirandaCount; i++, meth++) {
@@ -3875,17 +4001,32 @@
*
* What we need to do is ensure that the classes named in the method
* descriptors in our ancestors and ourselves resolve to the same class
- * objects. The only time this matters is when the classes come from
- * different class loaders, and the resolver might come up with a
- * different answer for the same class name depending on context.
+ * objects. We can get conflicts when the classes come from different
+ * class loaders, and the resolver comes up with different results for
+ * the same class name in different contexts.
*
- * We don't need to check to see if an interface's methods match with
- * its superinterface's methods, because you can't instantiate an
- * interface and do something inappropriate with it. If interface I1
- * extends I2 and is implemented by C, and I1 and I2 are in separate
- * class loaders and have conflicting views of other classes, we will
- * catch the conflict when we process C. Anything that implements I1 is
- * doomed to failure, but we don't need to catch that while processing I1.
+ * An easy way to cause the problem is to declare a base class that uses
+ * class Foo in a method signature (e.g. as the return type). Then,
+ * define a subclass and a different version of Foo, and load them from a
+ * different class loader. If the subclass overrides the method, it will
+ * have a different concept of what Foo is than its parent does, so even
+ * though the method signature strings are identical, they actually mean
+ * different things.
+ *
+ * A call to the method through a base-class reference would be treated
+ * differently than a call to the method through a subclass reference, which
+ * isn't the way polymorphism works, so we have to reject the subclass.
+ * If the subclass doesn't override the base method, then there's no
+ * problem, because calls through base-class references and subclass
+ * references end up in the same place.
+ *
+ * We don't need to check to see if an interface's methods match with its
+ * superinterface's methods, because you can't instantiate an interface
+ * and do something inappropriate with it. If interface I1 extends I2
+ * and is implemented by C, and I1 and I2 are in separate class loaders
+ * and have conflicting views of other classes, we will catch the conflict
+ * when we process C. Anything that implements I1 is doomed to failure,
+ * but we don't need to catch that while processing I1.
*
* On failure, throws an exception and returns "false".
*/
@@ -3903,15 +4044,18 @@
clazz->classLoader != clazz->super->classLoader)
{
/*
- * Walk through every method declared in the superclass, and
- * compare resolved descriptor components. We pull the Method
- * structs out of the vtable. It doesn't matter whether we get
- * the struct from the parent or child, since we just need the
- * UTF-8 descriptor, which must match.
+ * Walk through every overridden method and compare resolved
+ * descriptor components. We pull the Method structs out of
+ * the vtable. It doesn't matter whether we get the struct from
+ * the parent or child, since we just need the UTF-8 descriptor,
+ * which must match.
*
* We need to do this even for the stuff inherited from Object,
* because it's possible that the new class loader has redefined
* a basic class like String.
+ *
+ * We don't need to check stuff defined in a superclass because
+ * it was checked when the superclass was loaded.
*/
const Method* meth;
@@ -3920,7 +4064,9 @@
// clazz->super->descriptor, clazz->super->classLoader);
for (i = clazz->super->vtableCount - 1; i >= 0; i--) {
meth = clazz->vtable[i];
- if (!checkMethodDescriptorClasses(meth, clazz->super, clazz)) {
+ if (meth != clazz->super->vtable[i] &&
+ !checkMethodDescriptorClasses(meth, clazz->super, clazz))
+ {
LOGW("Method mismatch: %s in %s (cl=%p) and super %s (cl=%p)\n",
meth->name, clazz->descriptor, clazz->classLoader,
clazz->super->descriptor, clazz->super->classLoader);
@@ -3932,7 +4078,12 @@
}
/*
- * Check all interfaces we implement.
+ * Check the methods defined by this class against the interfaces it
+ * implements. If we inherited the implementation from a superclass,
+ * we have to check it against the superclass (which might be in a
+ * different class loader). If the superclass also implements the
+ * interface, we could skip the check since by definition it was
+ * performed when the class was loaded.
*/
for (i = 0; i < clazz->iftableCount; i++) {
const InterfaceEntry* iftable = &clazz->iftable[i];
@@ -3948,7 +4099,7 @@
vtableIndex = iftable->methodIndexArray[j];
meth = clazz->vtable[vtableIndex];
- if (!checkMethodDescriptorClasses(meth, iface, clazz)) {
+ if (!checkMethodDescriptorClasses(meth, iface, meth->clazz)) {
LOGW("Method mismatch: %s in %s (cl=%p) and "
"iface %s (cl=%p)\n",
meth->name, clazz->descriptor, clazz->classLoader,
@@ -4310,19 +4461,21 @@
/*
* Add a RegisterMap to a Method. This is done when we verify the class
- * and compute the register maps at class initialization time, which means
- * that "pMap" is on the heap and should be freed when the Method is
- * discarded.
+ * and compute the register maps at class initialization time (i.e. when
+ * we don't have a pre-generated map). This means "pMap" is on the heap
+ * and should be freed when the Method is discarded.
*/
void dvmSetRegisterMap(Method* method, const RegisterMap* pMap)
{
ClassObject* clazz = method->clazz;
if (method->registerMap != NULL) {
- LOGW("WARNING: registerMap already set for %s.%s\n",
+ /* unexpected during class loading, okay on first use (uncompress) */
+ LOGV("NOTE: registerMap already set for %s.%s\n",
method->clazz->descriptor, method->name);
/* keep going */
}
+ assert(!dvmIsNativeMethod(method) && !dvmIsAbstractMethod(method));
/* might be virtual or direct */
dvmLinearReadWrite(clazz->classLoader, clazz->virtualMethods);
diff --git a/vm/oo/Class.h b/vm/oo/Class.h
index 349df3f..59e0da4 100644
--- a/vm/oo/Class.h
+++ b/vm/oo/Class.h
@@ -149,8 +149,19 @@
*/
void dvmSetRegisterMap(Method* method, const RegisterMap* pMap);
-/* during DEX optimizing, add an extra DEX to the bootstrap class path */
-INLINE void dvmSetBootPathExtraDex(DvmDex* pDvmDex);
+/*
+ * Make a method's DexCode (which includes the bytecode) read-write or
+ * read-only. The conversion to read-write may involve making a new copy
+ * of the DexCode, and in normal operation the read-only state is not
+ * actually enforced.
+ */
+void dvmMakeCodeReadWrite(Method* meth);
+void dvmMakeCodeReadOnly(Method* meth);
+
+/*
+ * During DEX optimizing, add an extra DEX to the bootstrap class path.
+ */
+void dvmSetBootPathExtraDex(DvmDex* pDvmDex);
/*
* Debugging.
diff --git a/vm/oo/Object.c b/vm/oo/Object.c
index 189ad09..96493f7 100644
--- a/vm/oo/Object.c
+++ b/vm/oo/Object.c
@@ -90,18 +90,16 @@
assert(clazz != NULL);
+ /*
+ * Find a field with a matching name and signature. As with instance
+ * fields, the VM allows you to have two fields with the same name so
+ * long as they have different types.
+ */
pField = clazz->sfields;
for (i = 0; i < clazz->sfieldCount; i++, pField++) {
- if (strcmp(fieldName, pField->field.name) == 0) {
- /*
- * The name matches. Unlike methods, we can't have two fields
- * with the same names but differing types.
- */
- if (strcmp(signature, pField->field.signature) != 0) {
- LOGW("Found field '%s', but sig is '%s' not '%s'\n",
- fieldName, pField->field.signature, signature);
- return NULL;
- }
+ if (strcmp(fieldName, pField->field.name) == 0 &&
+ strcmp(signature, pField->field.signature) == 0)
+ {
return pField;
}
}
@@ -617,37 +615,44 @@
}
clazz = obj->clazz;
- LOGV("----- Object dump: %p (%s, %d bytes) -----\n",
+ LOGD("----- Object dump: %p (%s, %d bytes) -----\n",
obj, clazz->descriptor, (int) clazz->objectSize);
//printHexDump(obj, clazz->objectSize);
- LOGV(" Fields:\n");
- for (i = 0; i < clazz->ifieldCount; i++) {
- const InstField* pField = &clazz->ifields[i];
- char type = pField->field.signature[0];
+ LOGD(" Fields:\n");
+ while (clazz != NULL) {
+ LOGD(" -- %s\n", clazz->descriptor);
+ for (i = 0; i < clazz->ifieldCount; i++) {
+ const InstField* pField = &clazz->ifields[i];
+ char type = pField->field.signature[0];
- if (type == 'F' || type == 'D') {
- double dval;
+ if (type == 'F' || type == 'D') {
+ double dval;
- if (type == 'F')
- dval = dvmGetFieldFloat(obj, pField->byteOffset);
- else
- dval = dvmGetFieldDouble(obj, pField->byteOffset);
+ if (type == 'F')
+ dval = dvmGetFieldFloat(obj, pField->byteOffset);
+ else
+ dval = dvmGetFieldDouble(obj, pField->byteOffset);
- LOGV(" %2d: '%s' '%s' flg=%04x %.3f\n", i, pField->field.name,
- pField->field.signature, pField->field.accessFlags, dval);
- } else {
- long long lval;
+ LOGD(" %2d: '%s' '%s' af=%04x off=%d %.3f\n", i,
+ pField->field.name, pField->field.signature,
+ pField->field.accessFlags, pField->byteOffset, dval);
+ } else {
+ u8 lval;
- if (pField->field.signature[0] == 'J')
- lval = dvmGetFieldLong(obj, pField->byteOffset);
- else if (pField->field.signature[0] == 'Z')
- lval = dvmGetFieldBoolean(obj, pField->byteOffset);
- else
- lval = dvmGetFieldInt(obj, pField->byteOffset);
+ if (type == 'J')
+ lval = dvmGetFieldLong(obj, pField->byteOffset);
+ else if (type == 'Z')
+ lval = dvmGetFieldBoolean(obj, pField->byteOffset);
+ else
+ lval = dvmGetFieldInt(obj, pField->byteOffset);
- LOGV(" %2d: '%s' '%s' af=%04x 0x%llx\n", i, pField->field.name,
- pField->field.signature, pField->field.accessFlags, lval);
+ LOGD(" %2d: '%s' '%s' af=%04x off=%d 0x%08llx\n", i,
+ pField->field.name, pField->field.signature,
+ pField->field.accessFlags, pField->byteOffset, lval);
+ }
}
+
+ clazz = clazz->super;
}
}
diff --git a/vm/oo/Object.h b/vm/oo/Object.h
index 18fbb36..0bf2728 100644
--- a/vm/oo/Object.h
+++ b/vm/oo/Object.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Declaration of the fundamental Object type and refinements thereof, plus
* some functions for manipulating them.
@@ -93,6 +94,44 @@
#define EXPECTED_FILE_FLAGS \
(ACC_CLASS_MASK | CLASS_ISPREVERIFIED | CLASS_ISOPTIMIZED)
+/*
+ * Get/set class flags.
+ */
+#define SET_CLASS_FLAG(clazz, flag) \
+ do { (clazz)->accessFlags |= (flag); } while (0)
+
+#define CLEAR_CLASS_FLAG(clazz, flag) \
+ do { (clazz)->accessFlags &= ~(flag); } while (0)
+
+#define IS_CLASS_FLAG_SET(clazz, flag) \
+ (((clazz)->accessFlags & (flag)) != 0)
+
+#define GET_CLASS_FLAG_GROUP(clazz, flags) \
+ ((u4)((clazz)->accessFlags & (flags)))
+
+/*
+ * Use the top 16 bits of the access flags field for other method flags.
+ * Code should use the *METHOD_FLAG*() macros to set/get these flags.
+ */
+typedef enum MethodFlags {
+ METHOD_ISWRITABLE = (1<<31), // the method's code is writable
+} MethodFlags;
+
+/*
+ * Get/set method flags.
+ */
+#define SET_METHOD_FLAG(method, flag) \
+ do { (method)->accessFlags |= (flag); } while (0)
+
+#define CLEAR_METHOD_FLAG(method, flag) \
+ do { (method)->accessFlags &= ~(flag); } while (0)
+
+#define IS_METHOD_FLAG_SET(method, flag) \
+ (((method)->accessFlags & (flag)) != 0)
+
+#define GET_METHOD_FLAG_GROUP(method, flags) \
+ ((u4)((method)->accessFlags & (flags)))
+
/* current state of the class, increasing as we progress */
typedef enum ClassStatus {
CLASS_ERROR = -1,
@@ -134,14 +173,6 @@
#define PRIM_TYPE_TO_LETTER "ZCFDBSIJV" /* must match order in enum */
/*
- * 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.
- */
-#define CLASS_FIELD_SLOTS 4
-
-
-/*
* Used for iftable in ClassObject.
*/
typedef struct InterfaceEntry {
@@ -185,21 +216,6 @@
do { (obj)->clazz = (clazz_); DVM_LOCK_INIT(&(obj)->lock); } while (0)
/*
- * Get/set class flags.
- */
-#define SET_CLASS_FLAG(clazz, flag) \
- do { (clazz)->accessFlags |= (flag); } while (0)
-
-#define CLEAR_CLASS_FLAG(clazz, flag) \
- do { (clazz)->accessFlags &= ~(flag); } while (0)
-
-#define IS_CLASS_FLAG_SET(clazz, flag) \
- (((clazz)->accessFlags & (flag)) != 0)
-
-#define GET_CLASS_FLAG_GROUP(clazz, flags) \
- ((u4)((clazz)->accessFlags & (flags)))
-
-/*
* Data objects have an Object header followed by their instance data.
*/
struct DataObject {
@@ -262,6 +278,13 @@
};
/*
+ * 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.
+ */
+#define CLASS_FIELD_SLOTS 4
+
+/*
* Class objects have many additional fields. This is used for both
* classes and interfaces, including synthesized classes (arrays and
* primitive types).
diff --git a/vm/oo/Resolve.c b/vm/oo/Resolve.c
index 52eeee0..68fdd51 100644
--- a/vm/oo/Resolve.c
+++ b/vm/oo/Resolve.c
@@ -130,8 +130,11 @@
referrer->pDvmDex,
resClass->descriptor, resClassCheck->descriptor,
resClassCheck->classLoader, resClassCheck->pDvmDex);
+ LOGW("(%s had used a different %s during pre-verification)\n",
+ referrer->descriptor, resClass->descriptor);
dvmThrowException("Ljava/lang/IllegalAccessError;",
- "cross-loader access from pre-verified class");
+ "Class ref in pre-verified class resolved to unexpected "
+ "implementation");
return NULL;
}
}
diff --git a/vm/reflect/Reflect.c b/vm/reflect/Reflect.c
index b7de934..2e3c549 100644
--- a/vm/reflect/Reflect.c
+++ b/vm/reflect/Reflect.c
@@ -212,7 +212,7 @@
;
savedChar = *++signature;
*signature = '\0';
- clazz = dvmFindClass(*pSignature, defClass->classLoader);
+ clazz = dvmFindClassNoInit(*pSignature, defClass->classLoader);
*signature = savedChar;
} else {
clazz = dvmFindPrimitiveClass(*signature++);
diff --git a/vm/test/AtomicSpeed.c b/vm/test/AtomicSpeed.c
new file mode 100644
index 0000000..e2ffbef
--- /dev/null
+++ b/vm/test/AtomicSpeed.c
@@ -0,0 +1,115 @@
+/*
+ * 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/Test.h b/vm/test/Test.h
index a6b54a5..ce47aae 100644
--- a/vm/test/Test.h
+++ b/vm/test/Test.h
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Internal unit tests.
*/
@@ -20,5 +21,6 @@
#define _DALVIK_TEST_TEST
bool dvmTestHash(void);
+bool dvmTestAtomicSpeed(void);
#endif /*_DALVIK_TEST_TEST*/